require "global"

require "Bubble"
require "Field"

require "ResultPanel"
require "PausePanel"

local _userData = userData
local _pp = pp
local _gameData = gameData

math.randomseed(os.time())

local s_uiinfo = s_uiinfo or {}
s_uiinfo.startbb = UIInfo.create()
s_uiinfo.curbtbb = UIInfo.create()
s_uiinfo.nextbtbb = UIInfo.create()
s_uiinfo.fenjibt = UIInfo.create()
s_uiinfo.topline = UIInfo.create()
s_uiinfo.popWin = UIInfo.create()

local tmp_uiinfo = UIInfo.create()


local s_colCnt = 9
local s_bbVerticalInterval = 0.85
local s_bbSpeed = 1600
--local s_bbSpeed = 1300

local s_mapStartShow = 5.5   --3.5
local s_mapPlayReadyGoRowCnt = 15
local s_mapRaiseSpeed = (function() if not IS_UPFAST then return 1050 else return 4000 end end)()
local s_mapFallSpeedTbl = {
    {show = 0, speed = -300},
    {show = 3.5, speed = -170},
    {show = 4.5, speed = -65},
    {show = 6, speed = -51},
    {show = 7.5, speed = -41},
    {show = 9, speed = -31},
    {show = 11, speed = -24},
    {show = 12, speed = -16},
    {show = 13, speed = -12},
    {show = 100, speed = -8},
}
local s_deadLineRowCnt = 14.5
local s_deadLineWarning = 10

local s_fuhuoRowCnt = 7
local s_fuhuoRaiseSpeed = 500

local dirLT = 1
local dirRT = 2
local dirR = 3
local dirRB = 4
local dirLB = 5
local dirL = 6
local s_dirs = {dirLT,dirRT,dirR,dirRB,dirLB,dirL}

local s_COS30 = math.cos(math.rad(30))
local dirLT_vector = {x = -0.5, y = s_COS30}
local dirRT_vector = {x = 0.5, y = s_COS30}
local dirR_vector = {x = 1, y = 0}
local dirRB_vector = {x = 0.5, y = -s_COS30}
local dirLB_vector = {x = -0.5, y = -s_COS30}
local dirL_vector = {x = -1, y = 0}

--motionType
local mt_static = 0
local mt_dynamic = 1

--updown state
local UDS_none = 0
local UDS_up = 1
local UDS_down = 2

--six pos round bb center, init in GameScene:init()
local s_bbRoundPos = {}


------------------------------------------------------------
--
GameScene = class("GameScene", baseScene)

function GameScene.create()

    local scene = GameScene.new()
    scene:init()
    return scene
end

function GameScene:destroy()
    self.view:unscheduleUpdate()
    self = nil
    Field.all = nil
    AudioEngine.stopMusic()
end

function GameScene:init()

    gameData.changeSceneTimes.gameScene = gameData.changeSceneTimes.gameScene + 1
    --AudioEngine.setMusicVolume(1)


    -- local bgMusicPath = cc.FileUtils:getInstance():fullPathForFilename(music.game)
    -- cc.SimpleAudioEngine:getInstance():playMusic(bgMusicPath, true)

    ------------------------------------------------
    self.view = cc.Scene:create()

    gameData.status = pp.gamestate_playing

    self.mapbbOffsetY = 0
    self.bbLayer = nil
    self.cannon = nil
    self.bRasingMap = false
    self.curbt = nil    --current bullet bubble
    self.nextbt = nil   --next bullet bubble
    self.boss = nil
    self.bulletIdx = 0
    self.bulletRun = false
    self.curBtReady = false
    self.bulletDir = {}
    self.passedBbsThisBullet = {}
    self.bTripleUping = false --上一帧是否触发三消
    self.tup_speed = 20
    self.tup_dist = 15
    self.tup_passed = 0

    self.updown_state = UDS_none
    self.updown_speed = 40
    self.updown_dist = 30
    self.updown_passed = 0
    self.curLevel_downspeed = 1.0    --随关卡号，速度递增
    self.fuhuo_fallspeed_rate = (function() if not IS_LOWSPEED then return 1 else return 0.3 end end)()


    self.bbCntEachType = {[1]=0,[2]=0,[3]=0,[4]=0,[5]=0,[6]=0,[7]=0}


    self.ui_topline = nil
    self.ui_bossline = nil
    self.ui_top_fence = nil

    self.comb_time = 0      --连击计时器
    self.comb_cnt = 0       --连击数
    self.bCombing = false   --是否在连击状态中
    self.bbsExplodeEffectCastTime = 0  --泡泡消去效果持续的时间
    self.bNeedPlayCombUpSound = false

    self.ui_deadline = nil
    self.bDeadlineWarning = false
    self.ui_res_board = nil

    --鉴于一些优化，将某些graph,map逻辑放到下一帧执行，仅当他们执行完毕再进行一些逻辑判断
    --每进行一个延迟处理cnt+1，处理过后cnt-1，当cnt==0时，表示当前帧处理了全部的逻辑
    self.bGmProcessDelayCnt = 0
    self.bGmProcessing = false

    --relative windows
    -- self.pausePanel = nil
    self.warningPanel = nil

    self.guideProcessor = nil

    self.refcnt_gamepause = 0

    do  --const from ui json
        cc.SpriteFrameCache:getInstance():addSpriteFrames("ppdragon0.plist", "ppdragon0.png")
        -- cc.SpriteFrameCache:getInstance():addSpriteFrames("ppdragon1.plist", "ppdragon1.png")


        self.widget = ccs.GUIReader:getInstance():widgetFromJsonFile("gamescene.ExportJson")
        self.view:addChild(self.widget)

        do
            self.bbLayer = self.widget:getChildByName("_bb_layer")
    end

    do
        local view = self.widget:getChildByName("_pos_popwin")
        s_uiinfo.popWin:readInfoFromNode(view)
        view:removeFromParent(true)
    end


    do  --_touch_region
        self.touchRegion = self.widget:getChildByName("_touch_region")

        self.touchlayer = cc.Layer:create()
        self.widget:addChild(self.touchlayer, pp.z_touchRegion)

        d_print("init touchRegion")
        self.touchlayer:setTouchEnabled(true)

        local function onTouchBegan(touch, event)
            local region = self.touchRegion
            local location = touch:getLocation()
            if location.x > region:getPositionX() and
                location.x < region:getPositionX() + region:getContentSize().width*region:getScaleX() and
                location.y > region:getPositionY() and
                location.y < region:getPositionY() + region:getContentSize().height*region:getScaleY()
            then
                --d_print("touch began")
                return true
            else
                return false
            end
        end

        local function onTouchEnded(touch, event)
            local region = self.touchRegion
            local location = touch:getLocation()
            if location.x > region:getPositionX() and
                location.x < region:getPositionX() + region:getContentSize().width*region:getScaleX() and
                location.y > region:getPositionY() and
                location.y < region:getPositionY() + region:getContentSize().height*region:getScaleY()
            then
                self:onGameViewTouched(location)
            end
        end

        local listener = cc.EventListenerTouchOneByOne:create()
        --            listener:setSwallowTouches(true)
        listener:registerScriptHandler(onTouchBegan,cc.Handler.EVENT_TOUCH_BEGAN )
        listener:registerScriptHandler(onTouchEnded,cc.Handler.EVENT_TOUCH_ENDED )
        local eventDispatcher = self.view:getEventDispatcher()
        eventDispatcher:addEventListenerWithSceneGraphPriority(listener, self.touchlayer)
    end

    do --mask
        self.base_mask = self.widget:getChildByName("_mask")
        self.base_mask:setVisible(false)
    end

    -- if not IS_SHOW_GRID then    --debug grid
    --     local grid = self.widget:getChildByName("____grid")
    --     grid:removeFromParent()
    -- end

    do  --startbb
        local startbb = self.widget:getChildByName("_bubble_start")
        s_uiinfo.startbb:readInfoFromNode(startbb)

        Bubble.radius = startbb:getContentSize().width / 2
        Bubble.intervalY = Bubble.radius*s_COS30
        Bubble.dist = Bubble.intervalY*2
        Bubble.distSq = Bubble.dist * Bubble.dist

        s_bbRoundPos[dirRT] = {x = Bubble.radius, y = 2*Bubble.radius*s_COS30}
        s_bbRoundPos[dirR] = {x = 2*Bubble.radius, y = 0}
        s_bbRoundPos[dirRB] = {x = Bubble.radius, y = -2*Bubble.radius*s_COS30}
        s_bbRoundPos[dirLB] = {x = -Bubble.radius, y = -2*Bubble.radius*s_COS30}
        s_bbRoundPos[dirL] = {x = -2*Bubble.radius, y = 0}
        s_bbRoundPos[dirLT] = {x = -Bubble.radius, y = 2*Bubble.radius*s_COS30}

        GameScene.topBoundary = s_uiinfo.startbb.position.y + Bubble.radius

        startbb:removeFromParent()
    end

    do  --cur bt bb
        local bb = self.widget:getChildByName("_cur_bullet")
        s_uiinfo.curbtbb:readInfoFromNode(bb)
        bb:removeFromParent()
    end

    do  --next bt bb
        local bb = self.widget:getChildByName("_next_bullet")
        s_uiinfo.nextbtbb:readInfoFromNode(bb)
        bb:removeFromParent()

        local bg = self.widget:getChildByName("_next_bullet_bg")
        local repeatAction = cc.RepeatForever:create(cc.RotateBy:create(1.0, -180))
        bg:runAction(repeatAction)
    end

    do
        self.cannon = self.widget:getChildByName("_cannon")
    end

    do  --res board
        local view = self.widget:getChildByName("_res_container")
        self.resultPanel = ResultPanel.create(view)
        self.resultPanel.view:setVisible(false)
    end

    do  --topline
        self.ui_topline = self.widget:getChildByName("_topline")
        s_uiinfo.topline:readInfoFromNode(self.ui_topline)
        self.ui_top_fence = self.ui_topline
    end

    do --bossline
        self.ui_bossline = self.widget:getChildByName("_bossline")
        self.ui_bossline:setVisible(false)

        local xpprogress = self.ui_bossline:getChildByName("_xp")
        tmp_uiinfo:readInfoFromNode(xpprogress)
        xpprogress:removeFromParent(true)

        -- self.ui_boss_xpprogress = cc.Scale9Sprite:createWithSpriteFrameName("gamescene/hptiao.png")
        -- self.ui_boss_xp_preferredSize = self.ui_boss_xpprogress:getPreferredSize()
        -- self.ui_boss_xpprogress:setInsetLeft(8)
        -- self.ui_boss_xpprogress:setInsetRight(8)
        -- self.ui_boss_xpprogress:setPreferredSize(cc.size(0, self.ui_boss_xp_preferredSize.height))

        self.ui_boss_xpprogress = cc.ProgressTimer:create(cc.Sprite:createWithSpriteFrameName("gamescene/hptiao.png"))
        self.ui_boss_xpprogress:setType(cc.PROGRESS_TIMER_TYPE_BAR)
        self.ui_boss_xpprogress:setMidpoint(cc.p(0, 0))
        self.ui_boss_xpprogress:setBarChangeRate(cc.p(1, 0))

        tmp_uiinfo:setInfoToNode(self.ui_boss_xpprogress)
        self.ui_bossline:addChild(self.ui_boss_xpprogress)

        self.ui_boss_hp1 = self.ui_bossline:getChildByName("_hp1")
        self.ui_boss_hp2 = self.ui_bossline:getChildByName("_hp2")
        self.ui_boss_hp3 = self.ui_bossline:getChildByName("_hp3")
        self.ui_boss_hp4 = self.ui_bossline:getChildByName("_hp4")
    end

    do  --deadline
        self.ui_deadline = self.widget:getChildByName("_deadline")

    end


    do --top panel
        local ctn = self.widget:getChildByName("_top_container")

        --level
        local levelFnt = ctn:getChildByName("_fnt_level")
        tmp_uiinfo:readInfoFromNode(levelFnt)
        levelFnt:removeFromParent(true)
        self.ui_fnt_level = cc.LabelBMFont:create("0",  pp.fnt_number_white)
        --            self.ui_fnt_level:set
        tmp_uiinfo:setInfoToNode(self.ui_fnt_level)
        self.ui_fnt_level:setScale(0.55)
        --self.ui_fnt_level:setPosition(0,0)
        ctn:addChild(self.ui_fnt_level)


        --coin
        local coinFnt = ctn:getChildByName("_fnt_coin")
        tmp_uiinfo:readInfoFromNode(coinFnt)
        coinFnt:removeFromParent(true)

        self.ui_fnt_coin = cc.LabelBMFont:create(string.format("%d",userData.coin), pp.fnt_number_white, 100, cc.TEXT_ALIGNMENT_LEFT)

        tmp_uiinfo:setInfoToNode(self.ui_fnt_coin)
        self.ui_fnt_coin:setScale(0.45);
        ctn:addChild(self.ui_fnt_coin)

        --score
        local scoreFnt = ctn:getChildByName("_fnt_score")
        tmp_uiinfo:readInfoFromNode(scoreFnt)
        scoreFnt:removeFromParent(true)

        self.ui_fnt_score = cc.LabelBMFont:create("0",  pp.fnt_number_white)
        tmp_uiinfo:setInfoToNode(self.ui_fnt_score)
        self.ui_fnt_score:setScale(0.45);
        ctn:addChild(self.ui_fnt_score)

        --score progress
        local scoreprogress = ctn:getChildByName("_score_inner")
        tmp_uiinfo:readInfoFromNode(scoreprogress)
        scoreprogress:removeFromParent(true)

        self.ui_scoreprogress = cc.ProgressTimer:create(cc.Sprite:createWithSpriteFrameName("gamescene/score_inner.png"))
        self.ui_scoreprogress:setType(cc.PROGRESS_TIMER_TYPE_BAR)
        self.ui_scoreprogress:setMidpoint(cc.p(0, 0))
        self.ui_scoreprogress:setBarChangeRate(cc.p(1, 0))

        tmp_uiinfo:setInfoToNode(self.ui_scoreprogress)
        ctn:addChild(self.ui_scoreprogress)

        --pause bt
        local function btPauseCallback(sender, eventType)
            if eventType == ccui.TouchEventType.began then
                AudioEngine.playEffect(sound.btn1)

            elseif eventType == ccui.TouchEventType.ended then
                self:onClickPause()
            end
        end
        local bt_pause = ctn:getChildByName("_pause")
        bt_pause:addTouchEventListener(btPauseCallback)


    end

    do  --score

    end

    do  --bt weapon
        local function btYuhengCallback(sender, eventType)
            if eventType == ccui.TouchEventType.began then
                AudioEngine.playEffect(sound.btn1)

            elseif eventType == ccui.TouchEventType.ended then
                self:doYuhengCallback()
            end
        end
    
        self.bt_yuheng = self.widget:getChildByName("_bt_yuheng")
        self.bt_yuheng:addTouchEventListener(btYuhengCallback)

        self.ui_weaponCnt_yuheng = uiUtil.createBMFontByHolder(self.bt_yuheng, "_cnt", pp.fnt_number_yellow)
        self.ui_weaponCnt_yuheng:setScale(0.6)
        self.ui_weaponCnt_yuheng:setString(string.format("%d", userData.weaponCnt_yuheng))
        

        if gameData.level <= guideCfg.globeConst.yuhengUnlockLevel then --待到某个关卡解锁，之后的关卡才显示
            self.bt_yuheng:setVisible(false)
        else --解锁后，加上醒目旋转特效
            --ani yuheng
            local yhx,yhy = self.bt_yuheng:getPosition()
            local foreverrot = cc.RepeatForever:create(cc.RotateBy:create(1, -180))
            local imageZhuan = ccui.ImageView:create("ani/daojuzhuan.png", ccui.TextureResType.localType)
            local offset = self.bt_yuheng:getContentSize().width*0.5
            self.bt_yuheng:addChild(imageZhuan,1)
            imageZhuan:runAction(foreverrot)
            imageZhuan:setPosition(offset,offset)
        end

        ----

        local function btFenjiCallback(sender, eventType)
            if eventType == ccui.TouchEventType.began then
                AudioEngine.playEffect(sound.btn1)

            elseif eventType == ccui.TouchEventType.ended then
                self:doFenjiCallback()
            end
        end
        self.bt_fenji = self.widget:getChildByName("_bt_fenji")
        self.bt_fenji:addTouchEventListener(btFenjiCallback)
        s_uiinfo.fenjibt:readInfoFromNode(self.bt_fenji)

        self.ui_weaponCnt_fenji = uiUtil.createBMFontByHolder(self.bt_fenji, "_cnt", pp.fnt_number_yellow)
        self.ui_weaponCnt_fenji:setScale(0.6)

        if gameData.level <= guideCfg.globeConst.fenjiUnlockLevel then --待到某个关卡解锁，之后的关卡才显示
            self.bt_fenji:setVisible(false)
        end

    end
        self:refreshWeaponCnt()

    end


    --    local scheduler = cc.Director:getInstance():getScheduler()
    --    scheduler:scheduleScriptFunc(function() self:step() end, 0,false)

    local function update(delta)
        self:update(delta)
    end
    self.view:scheduleUpdateWithPriorityLua(update, 0)

    local function onNodeEvent(event)
        if "exit" == event then
            --lkj temp: 重入的时候会先enter，后exit，导致这里贴图释放，先注掉
            if not IS_DEBUG  then
            --cc.SpriteFrameCache:getInstance():removeSpriteFramesFromFile("image/ppdragon0.plist")
            end
        elseif "enter" == event then
            if self.boss then
                self.boss:startAttack()
                self.ui_topline:setVisible(false)
                self.ui_bossline:setVisible(true)
                self.ui_top_fence = self.ui_bossline
                local hpcnt = gameData.leveldata.boss.life
                local hpimage = {self.ui_boss_hp1, self.ui_boss_hp2, self.ui_boss_hp3, self.ui_boss_hp4}
                for i = hpcnt+1,4 do
                    hpimage[i]:setVisible(false)
                end
            else
                self.ui_topline:setVisible(true)
                self.ui_bossline:setVisible(false)
                self.ui_top_fence = self.ui_topline
            end

            gameUtil.playMusic(music.game, true)
        end
    end
    self.view:registerScriptHandler(onNodeEvent)



    --key
    local function onKeyReleased(keyCode, event)
        local view = event:getCurrentTarget()
        if keyCode == cc.KeyCode.KEY_ESCAPE then

            AudioEngine.playEffect(sound.btn1)

            --弹出“离开”
            -- local win = self:base_isWinOpened("WarningPanel")
            -- if not win then
            --     local win = WarningPanel.create(self, "Common_leaveApp", pp.z_leaveApp)

            --     if #self.base_popWinStack == 1 then
            --         self:game_pause()
            --     end
            -- else
                
            --     if #self.base_popWinStack == 1 then
            --         if win.typekey == "Pay_game_FuHuo" then
            --             self:game_fail()
            --         else
            --             self:game_resume_callback()
            --         end
            --     end
            --     win:close()
            -- end

            --弹出“暂停”
            if #self.base_popWinStack == 0 then
                local pausePanel = PausePanel.create(self)
                pausePanel.view:setPosition(s_uiinfo.popWin.position.x, s_uiinfo.popWin.position.y)
                self:game_pause()
            elseif #self.base_popWinStack == 1 then
                local win = self.base_popWinStack[1]
                if win.typekey == "Pay_game_FuHuo" or 
                    win.typekey == "Pay_game_Libao_Fuhuo" or
                    win.typekey == "Pay_game_Libao_Fuhuo2" or 
                    win.typekey == "GameScene_freeFuhuo" then
                    self:game_fail()
                    win:close()
                elseif win.typekey == "Pay_ChangwanGift" then
                    win:close()
                    if gameData.status == _pp.gamestate_fail then
                        if userData.spe_freeFuhuoLeft == 0 then
                            WarningPanel.create(self, "Pay_game_Libao_Fuhuo")
                        else
                            self:wrapper_WarningPanel_create_freeFuhuo()
                        end
                    else
                        self:game_win(0)
                    end
                elseif win.class.__cname == "PausePanel" then
                    self:game_resume_callback()
                    win:close()
                end

            end
 
        end

    end
    local listener = cc.EventListenerKeyboard:create()
    listener:registerScriptHandler(onKeyReleased, cc.Handler.EVENT_KEYBOARD_RELEASED )
    local eventDispatcher = self.view:getEventDispatcher()
    eventDispatcher:addEventListenerWithSceneGraphPriority(listener, self.view)



    --game logic init
    gameData:initForGame()
    self.needPlay_ReadyGo = true
end

function GameScene:doYuhengCallback()
    if self.curBtReady == true and self.bGmProcessing == false then
        if userData.weaponCnt_yuheng > 0 then
            gameData.status = _pp.gamestate_weaponing
            
            self:weapon_yuheng()
            userData.weaponCnt_yuheng = userData.weaponCnt_yuheng - 1
            self:refreshWeaponCnt()
            
            self.bt_yuheng:setEnabled(false)
            self.bt_yuheng:setColor(cc.c3b(128,128,128))
            local function enable()
                self.bt_yuheng:setEnabled(true)
                self.bt_yuheng:setColor(cc.c3b(255,255,255))
            end
            performWithDelay(self.view, enable, _pp.weapon_cd)     

            gameUtil.sendGameStat(et.Level_Yuheng, userData.weaponLv_yuheng, userData.weaponCnt_yuheng)                  
        else
            self:game_pause()
            WarningPanel.create(self, "Pay_game_buyYuheng")
        end
    end
end

function GameScene:doFenjiCallback()
    if self.curBtReady == true and self.bGmProcessing == false and self.curbt.itype ~= _pp.bt_fenji then
        if userData.weaponCnt_fenji > 0 then
            self:weapon_fenji()
            userData.weaponCnt_fenji = userData.weaponCnt_fenji - 1
            self:refreshWeaponCnt()

            self.bt_fenji:setEnabled(false)
            self.bt_fenji:setColor(cc.c3b(128,128,128))
            local function enable()
                self.bt_fenji:setEnabled(true)
                self.bt_fenji:setColor(cc.c3b(255,255,255))
            end
            performWithDelay(self.view, enable, _pp.weapon_cd)

            gameData.status = _pp.gamestate_weaponing

            gameUtil.sendGameStat(et.Level_Fenji, userData.weaponLv_fenji, userData.weaponCnt_fenji)
        else
            self:game_pause()
            WarningPanel.create(self, "Pay_game_buyFenji")
        end
    end
end

function GameScene.nodeIndex(row, col)
    return (row-1)*s_colCnt + col
end

function GameScene:getbb(row, col)
    if self.levelbubbles[row] and self.levelbubbles[row][col] and self.levelbubbles[row][col] ~= 0 then
        return self.levelbubbles[row][col]
    else
        return nil
    end
end


function GameScene:graph_make(bb, dirs)
    local adjbbs = self:getAroundBBs_withDirs(bb, dirs)
    self:graph_makeEx(bb ,adjbbs)
end

function GameScene:graph_makeEx(bb, adjbbs)

    -- bb.field.elm = {}
    -- bb.field.isEnd = false          --图的边缘，这里是顶到top的泡泡
    -- bb.field.adj = {}               --临近fields

    local _pp = pp
    if bb.itype >= _pp.bt_comStart and bb.itype <= _pp.bt_comEnd then
        for k,v in pairs(adjbbs) do
            if v.itype == bb.itype then
                if bb.field == nil and v.field then --第一次找到同色区域
                    v.field:addElement(bb)
                elseif bb.field and v.field then --找到相同颜色的另外的区域，合并这个区域的元素，并丢弃掉这个多余的区域
                    --     notsame(lt) --- same(lr)
                    --       /           /
                    --      /           /
                    -- same(l)  ---  same(new)
                    if v.field ~= bb.field then
                        bb.field:concat(v.field)      --合并
                end
                end
            end
        end
    elseif bb.itype == _pp.bt_mixed then
    --彩泡作为一个单独的区分类
    else
        --其它泡一起作为一个区分类
        --d_print("bb type == "..bb.itype)
        for k,v in pairs(adjbbs)do
            if (v.itype < _pp.bt_comStart or v.itype > _pp.bt_comEnd) and v.itype ~= _pp.bt_mixed then
                if bb.field == nil and v.field then
                    v.field:addElement(bb)
                elseif bb.field and v.field then
                    if v.field ~= bb.field then
                        bb.field:concat(v.field)
                    end
                end
            end
        end
    end

    if not bb.field then
        bb.field = Field.create()
        bb.field:addElement(bb)
        if bb.row == 1 then
            bb.field:setEnd(true)
        end
    end

    --添加adj信息
    for k,v in pairs(adjbbs) do
        if v and v.field and bb.field ~= v.field then
            v.field:addAdjEach(bb.field)
        end
    end

end

function GameScene:graph_remove_field(field)
    field:removeSelf()
end

--lkj note:需要先update  levelbb的信息
function GameScene:graph_remove_bbs(bbs)
    local fields_remove = {}
    local needRegraphBbs = {}
    local fields_needChk = {}

    for k,v in pairs(bbs)do
        local elm = v.field.elm
        v.f_explodeOut = true               --lkj knowledge: 插入一个临时的flag,用完删除
        fields_remove[v.field] = true
    end

    for k,v in pairs(fields_remove)do
        for m,n in pairs(k.elm)do
            n.field = nil
            if n.f_explodeOut == nil then
                needRegraphBbs[#needRegraphBbs+1] = n
            else
                n.f_explodeOut = nil
            end
        end
        for m,n in pairs(k.adj)do
            if fields_remove[m] == nil then
                fields_needChk[m] = true
            end
        end
        k:removeSelf()
    end

    local all = Field.all
    local oldsize = #all

    for k,v in pairs(needRegraphBbs)do
        local dirs = {dirLT,dirRT,dirR,dirRB,dirLB,dirL}
        self:graph_make(v, dirs)
    end

    local newsize = #all
    for i = oldsize + 1, newsize, 1 do
        fields_needChk[all[i]] = true
    end
    return fields_needChk
end

function GameScene:getAroundBBs_withDirs(bb, dirs)
    local aroundbbs = {}
    for k,v in pairs(dirs) do
        local r,c = self:getBB_around_rc(bb.row, bb.col, v)
        local aroundbb = self:getbb(r,c)
        if aroundbb --[[and aroundbb.itype >= pp.bt_comStart and aroundbb.itype <= pp.bt_comEnd ]] then
            aroundbbs[#aroundbbs+1] = aroundbb
        end
    end
    return aroundbbs
end

function GameScene:readLevel(level)
    local levelstr = string.format("res/levels/level_%d.lua",level)
    _gameData.leveldata = require(levelstr)
    _gameData.historyScore = userData.passedlevelinfo[level].score

    -----------------------------------------------------
    self.levelbubbles = {}

    local startpos = s_uiinfo.startbb.position
    local dirs = {dirL, dirLT, dirRT}
    for i = 1, #_gameData.leveldata do
        self.levelbubbles[i] = {}

        local offsety = -(i-1)*Bubble.radius * 2*s_bbVerticalInterval
        local lineoffsetx = 0
        if i%2 == 0 then
            lineoffsetx = Bubble.radius
        end
        for j = 1, #_gameData.leveldata[i] do
            local bbtype = _gameData.leveldata[i][j]
            local bb = s_createBBbyType(bbtype)

            if bb == nil then
                self.levelbubbles[i][j] = 0
            else
                self.bbLayer:addChild(bb.view)
                bb.view:setLocalZOrder(pp.z_mapbb)
                self:bb_attachToMap(bb, i, j, true)
            end

            if bbtype == _pp.bt_boss then
                self.boss = bb
            end
        end
    end

    local visibleSize = pp.visibleSize
    self:moveMapBBsTo(-visibleSize.height)
    self.bRasingMap = true

    --[[dump graph
    Field.dumpGraph(self.levelbubbles)
    --]]

    -----------------------------------------------------

    self.prebullet = _gameData.leveldata.prebullet
    self.star_score = _gameData.leveldata.star_score

    self.curLevel_downspeed = _pp.level_speed_rate + level * _pp.per_level_speedup

    ---------------------------------------------
    local levelstring = string.format("%d", _gameData.level)
    self.ui_fnt_level:setString(levelstring)

    ----------------------------------------------
    --star poses
    local topctn = self.widget:getChildByName("_top_container")
    self.progress_star1 = topctn:getChildByName("_star1")
    self.progress_star2 = topctn:getChildByName("_star2")
    self.progress_star3 = topctn:getChildByName("_star3")

    local left = self.progress_star1:getPositionX()
    local right = self.progress_star3:getPositionX()

    local pct1 = self.star_score[1] / self.star_score[3]
    local pct2 = self.star_score[2] / self.star_score[3]

    local pos1 = left + (right - left)*pct1
    local pos2 = left + (right - left)*pct2

    self.progress_star1:setPositionX(pos1)
    self.progress_star2:setPositionX(pos2)
end

function GameScene:score_Raise(val)
    gameData.curScore = gameData.curScore + val
    local curstring = string.format("%d", gameData.curScore)
    self.ui_fnt_score:setString(curstring)


    --lkj test
    --    local tm = os.date("*t")
    --    print(tm.year.."."..tm.month.."."..tm.day.." "..tm.hour..":"..tm.min..":"..tm.sec)
    --
    --
    --    local sec = os.time{year = tm.year, month = tm.month, day = tm.day, hour = tm.hour, min = tm.min, sec = tm.sec}
    --    print("sec = "..sec)
    --    local nextsec = sec + 10*60
    --    local nexttm = os.date("*t", 10*60)
    --    print(nexttm.year.."."..nexttm.month.."."..nexttm.day.." "..nexttm.hour..":"..nexttm.min..":"..nexttm.sec)
    --
    --    local timestring = string.format("%d.%d.%d %d%d%d", nexttm.year,nexttm.month,nexttm.day,nexttm.hour,nexttm.min,nexttm.sec)
    --
    --    self.ui_fnt_score:setString(timestring)



    local stars = {self.progress_star1, self.progress_star2, self.progress_star3}

    local pct = gameData.curScore / self.star_score[3]
    if pct > 1 then pct=1 end
    self.ui_scoreprogress:setPercentage(pct*100)

    for k,v in ipairs(self.star_score)do
        if gameData.curScore > v then
            gameData.curStars = k
            stars[k]:loadTexture("common/xiaoxx.png", ccui.TextureResType.plistType)
        else
            break
        end
    end
end

function GameScene:score_setToOneStar()
    local pct = self.star_score[1] / self.star_score[3]
    self.ui_scoreprogress:setPercentage(pct*100)
    gameData.curScore = self.star_score[1]
    gameData.curStars = 1
end

function GameScene:data_coinRaise(val)
    userData.coin = userData.coin + val
    self:refreshCoin()
end

function GameScene:refreshCoin()
    local curstring = string.format("%d", userData.coin)
    self.ui_fnt_coin:setString(curstring)
end

function GameScene:getBBsShowHeight()
    local rowcnt = #self.levelbubbles
    local mapheight = rowcnt*Bubble.dist
    return mapheight - self.mapbbOffsetY
end

function GameScene:moveMapBBsTo(h)
    if IS_EDITOR_MODE then
        return
    end
    self.mapbbOffsetY = h
    self.ui_top_fence:setPositionY(s_uiinfo.topline.position.y + self.mapbbOffsetY)
    self.bbLayer:setPositionY(self.mapbbOffsetY)
end

function GameScene:moveMapBBsBy(h)
    if IS_EDITOR_MODE then
        return
    end
    self.mapbbOffsetY = self.mapbbOffsetY + h
    self.ui_top_fence:setPositionY(s_uiinfo.topline.position.y + self.mapbbOffsetY)
    self.bbLayer:setPositionY(self.mapbbOffsetY)
end

function GameScene:generateBulletBB()
    self.bulletIdx = self.bulletIdx + 1

    local itype
    if self.prebullet and self.bulletIdx <= #self.prebullet then
        itype = self.prebullet[self.bulletIdx]
    else
        local randomWeaponRD = math.random()            --随机武器:炸弹，彩球
        local boomCur = pp.weapon_boom_occur[userData.weaponLv_boom]
        local colorfulCur = pp.weapon_colorful_occur[userData.weaponLv_colorful]

        if randomWeaponRD < boomCur then
            itype = _pp.bt_boom
        elseif randomWeaponRD < boomCur + colorfulCur then
            itype = _pp.bt_mixed
        else                            --从已有色中随出一种
            local typecnt = 0
            local mapExistTypecnt = {}
            for k,v in ipairs(self.bbCntEachType)do
                if v > 0 then
                    typecnt = typecnt + 1
                    mapExistTypecnt[#mapExistTypecnt+1] = k
                end
            end
            local typeidx = math.random(#mapExistTypecnt)
            itype = mapExistTypecnt[typeidx]
        end
    end

    if itype == nil then
        itype = math.random(pp.bt_comEnd)
        assert(itype ~= 0)
    end

    assert(self.curbt == nil)
    if self.curbt == nil then
        if self.nextbt == nil then
            self.nextbt = s_createBBbyType(itype)
            self.widget:addChild(self.nextbt.view, pp.z_bullet)
            self.nextbt.view:setPosition(s_uiinfo.nextbtbb.position.x, s_uiinfo.nextbtbb.position.y)
            uiEffect.bounceIn(self.nextbt.view)
            return
        else
            --ani nextpos->curpos
            self.curbt = self.nextbt
            self.curbt.view:runAction(cc.Sequence:create(
                cc.MoveTo:create(0.2, s_uiinfo.curbtbb.position)
                , cc.CallFunc:create(function()
                                        self.curBtReady = true 
                                        --check guide
                                        if DEF_GUIDE then
                                            self:guide_OnBtReady_checkNext()   --lkj special:把新手指引检测
                                        end
                                    end
                     )
            ))

            --ani gen nextbb
            --d_print("s_createBBbyType: "..itype)
            self.nextbt = s_createBBbyType(itype)
            self.widget:addChild(self.nextbt.view, pp.z_bullet)
            self.nextbt.view:setPosition(s_uiinfo.nextbtbb.position.x, s_uiinfo.nextbtbb.position.y)
            uiEffect.bounceIn(self.nextbt.view)
        end
    end
end

function GameScene:guide_OnBtReady_checkNext()
    -- assert(not self.guideProcessor)
    if not self.guideProcessor then
        for k,v in ipairs(guideCfg.itemsOnBtReady) do
            if userData.passedlevelinfo[gameData.level].score == 0 then
                if v.condition and v.condition.level == gameData.level then
                    
                    local bGuide = false
                    if v.condition.mapOffset then
                        if self.mapbbOffsetY < v.condition.mapOffset then 
                            bGuide = true
                        end
                    else
                        bGuide = true
                    end

                    if bGuide then
                        self.guideProcessor = GuideProcessor.create(v)
                        self.guideProcessor:begin()
                        guideCfg.itemsOnBtReady[k] = "finish" --lkj note: 删除信息
                        return
                    end
                end
            end
        end
    end
end

function GameScene:guide_OnMapOffsetBelow_checkNext()
    assert(not self.guideProcessor)

    for k,v in ipairs(guideCfg.itemsOnMapOffset) do
        if userData.passedlevelinfo[gameData.level].score == 0 then
            if v.condition and v.condition.level == gameData.level then
                if self.mapbbOffsetY < v.condition.mapOffset then
                    self.guideProcessor = GuideProcessor.create(v)
                    self.guideProcessor:begin()
                    guideCfg.itemsOnMapOffset[k] = "finish" --lkj note: 删除信息
                    return
                end
            end
        end
    end
end

function GameScene:guide_itemFinish()
    assert(self.guideProcessor)
    self.guideProcessor:finish()
    self.guideProcessor = nil
end

function GameScene:prepareBullet_once()
    local function genBt(sender)
        self:generateBulletBB()
    end

    self.view:runAction( cc.Sequence:create(
        cc.CallFunc:create(genBt),
        cc.DelayTime:create(0.2),
        cc.CallFunc:create(genBt)))
end


function GameScene:adjustToTopwall(innerx)
    local destCol = (innerx + Bubble.radius) / (Bubble.radius*2)
    destCol = math.ceil(destCol)
    if destCol > 9 then
        destCol = 9
    end

    d_print("top destCol=="..destCol)
    assert(self.levelbubbles[1] ~= nil,"")
    if self.levelbubbles[1][destCol] ~=0 then
        d_print("error top destCell=="..destCol)
    end

    if IS_DEBUG then
        local _bb = self.levelbubbles[1][destCol]
        if type(_bb) == "table" then
            d_print("bb itype ==".._bb.itype)
        end
        assert(_bb ==0 or _bb.itype == 13 or _bb.itype == 14)
    end

    local poskey
    local innerdestx = Bubble.radius * (destCol - 1)*2
    if innerx < innerdestx then
        poskey = dirR
    else
        poskey = dirL
    end

    local leftwall = s_uiinfo.startbb.position.x
    local destx = leftwall + innerdestx
    return destCol,destx,poskey
end

local s_maxDelta = 0.015
function GameScene:update(delta)
    --start raise map
    if self.bRasingMap == true and not IS_EDITOR_MODE then
        local deltaY = s_mapRaiseSpeed * delta
        self:moveMapBBsBy(deltaY)

        local showheight = self:getBBsShowHeight()
        if self.needPlay_ReadyGo and showheight < Bubble.dist * s_mapPlayReadyGoRowCnt  then
            AudioEngine.playEffect(sound.readyGo)
            self.needPlay_ReadyGo = nil
        end

        if showheight < Bubble.dist * s_mapStartShow then
            self.bRasingMap = false
            gameData.status = pp.gamestate_playing

            self:prepareBullet_once()
        end

        return
    end

    --
    if gameData.status == pp.gamestate_win then
        return
    elseif gameData.status == pp.gamestate_fail then
        return
    end

    --
    if self.bGmProcessing == true and self.bGmProcessDelayCnt == 0 then
        self:cleanMapGap()
        self.bGmProcessing = false
    end


    --comb
    if self.bCombing == true then
        self.comb_time = self.comb_time + delta
        if self.comb_time > _pp.comb_maxInterval then
            self.bCombing = false
            self.comb_cnt = 0
            self.comb_time = 0
        end
    end


    -- map fall
    if not IS_EDITOR_MODE then
        local showheight = self:getBBsShowHeight()

        --fuhuo
        local fuhuoUp = 0
        if gameData.status == _pp.gamestate_fuhuoing then
            if showheight > Bubble.dist *s_fuhuoRowCnt then
                fuhuoUp = s_fuhuoRaiseSpeed*delta
            else
                gameData.status = _pp.gamestate_playing
            end
        else
        
            --fail
            if showheight > Bubble.dist *s_deadLineRowCnt and self.bGmProcessDelayCnt == 0 then
                d_print("game fail!!!")
                self:onGameFail()
                return
            end
            
        end

        
        --deadline status
        if self.bDeadlineWarning == false then
            if showheight > Bubble.dist*s_deadLineWarning then
                local tint_dark = cc.TintTo:create(0.5, 148, 148, 148)
                local tint_light = cc.TintTo:create(0.5, 255,255,255)
                local seq = cc.Sequence:create(tint_dark, tint_light)
                self.ui_deadline:runAction(cc.RepeatForever:create(seq))
                self.bDeadlineWarning = true
            end
        else
            if showheight < Bubble.dist*s_deadLineWarning then
                self.ui_deadline:stopAllActions()
                self.bDeadlineWarning = false
            end
        end

        --日常下降
        local runtineDown = 0
        if gameData.status ~= _pp.gamestate_weaponing then
            local fuhuolibao_speedIdx
            if userData.spe_bought_doubleFuhuoLibao +1 > #_pp.spe_doubleFuhuoSpeedRate then
                fuhuolibao_speedIdx = #_pp.spe_doubleFuhuoSpeedRate
            else
                fuhuolibao_speedIdx = userData.spe_bought_doubleFuhuoLibao + 1
            end

            for k,v in ipairs(s_mapFallSpeedTbl)do
                if showheight < v.show * Bubble.dist then
                    runtineDown = v.speed *(1-_pp.weapon_huanman_rate[userData.weaponLv_huanman])*delta * self.curLevel_downspeed *self.fuhuo_fallspeed_rate* _pp.spe_doubleFuhuoSpeedRate[fuhuolibao_speedIdx]
                    break
                end
            end
        end

        --上推、下推球触发的
        local updownThisFrame = 0
        local function __calc_updown()
            updownThisFrame = self.updown_speed*delta
            if self.updown_passed + updownThisFrame > self.updown_dist then
                updownThisFrame = self.updown_dist - self.updown_passed
                self.updown_state = UDS_none
            end
            self.updown_passed = self.updown_passed + updownThisFrame
        end
        if self.updown_state == UDS_up then
            __calc_updown()
        elseif self.updown_state == UDS_down then
            __calc_updown()
            updownThisFrame = -updownThisFrame
        end

        --同色消除后奖励的上推
        local tripleup = 0
        if self.bTripleUping == true then
            tripleup = self.tup_speed*delta
            if self.tup_passed + tripleup > self.tup_dist then
                tripleup = self.tup_dist - self.tup_passed
                self.bTripleUping = false
            end
            self.tup_passed = self.tup_passed + tripleup
        end

        self:moveMapBBsBy(runtineDown + updownThisFrame + tripleup + fuhuoUp)
    end



    local function motionUpdate(delta)

        --
        if self.bulletRun == true then
            local dirspeed = cc.pMul(self.bulletDir, s_bbSpeed)
            local curpos = {}
            curpos.x, curpos.y = self.curbt.view:getPosition()
            local dest = cc.pAdd(curpos, cc.pMul(dirspeed, delta))

            --hit side?
            do
                local leftwall = s_uiinfo.startbb.position.x
                local rightwall = (s_colCnt + 0.5)*Bubble.radius*2
                -- local topwall = s_uiinfo.startbb.position.y + self.mapbbOffsetY

                if dest.x < leftwall then
                    dest.x = leftwall + (leftwall - dest.x)
                    self.bulletDir.x = -self.bulletDir.x
                elseif dest.x > rightwall then
                    dest.x = rightwall - (dest.x - rightwall)
                    self.bulletDir.x = -self.bulletDir.x
                end
                assert(dest.x > 0, "update..dest.x < 0")

            end

            -------------------------------------------------------------------
            -------------------------------------------------------------------
            --hit bb?

            local rowidx_collision = -1
            local colidx_collision = -1
            local isCollide = false

            local passableBbs = {}


            --new optimize
            local maxRowCnt = #self.levelbubbles

            local destRealRow = (GameScene.topBoundary - dest.y + self.mapbbOffsetY - Bubble.radius) / Bubble.dist
            local midRow = math.ceil(destRealRow)


            local maxconRow, minconRow = midRow,midRow
            if midRow <= maxRowCnt then
                if midRow +1 <= maxRowCnt then
                    maxconRow = midRow+1
                end
                if midRow - 1 >= 1 then
                    minconRow = midRow - 1
                end
            elseif midRow == maxRowCnt + 1 then
                maxconRow,minconRow = maxRowCnt, maxRowCnt
            end



            local destRealCol = (dest.x - s_uiinfo.startbb.position.x) / (Bubble.radius*2)
            local midCol = math.ceil(destRealCol)   --偶数行还需往左多判断一列

            local maxconCol ,minconCol = midCol,midCol
            if midCol + 1 <= s_colCnt then
                maxconCol = midCol+1
            end
            if midCol - destRealCol < 0.5 and midCol - 1 >= 1 then
                minconCol = midCol - 1
            end

            --lkj test:
            --  local randttt = 0
            -- for i = 1, 4000 do
            --      randttt = randttt+ math.random(100)
            -- --    local tm = os.date("*t")
            --     --local cursec = os.time(tm)
            -- end


            for rowidx = maxconRow, minconRow, -1 do
                local row = self.levelbubbles[rowidx]
                if  row and type(row) == "table" then

                    for colidx = minconCol, maxconCol, 1 do
                        local v = row[colidx]
                        if type(v) == "table" then

                            if v.itype then
                                local pos = {}

                                --lkj note:这里换做对应行列的方式来取位置，是因为boss发射泡泡的时候在发射瞬间，已经决定了泡泡的行列归属，但是泡泡的实际没有到达最终位置，这样子弹可能检测不到碰撞，而射到这个实际已经存在泡泡的位置了
                                --pos.x, pos.y = v.view:getPosition()
                                --replace with below
                                pos.x, pos.y = GameScene.bb_pos(rowidx,colidx)

                                pos.y = pos.y + self.mapbbOffsetY
                                local distSQ = math.pow(pos.x - dest.x,2) + math.pow(pos.y - dest.y,2)

                                local tolerance = 200
                                if distSQ < Bubble.distSq + tolerance then

                                    if v.passable == false or self.curbt.itype == _pp.bt_boom then
                                        self.bulletRun = false
                                        rowidx_collision = rowidx
                                        colidx_collision = colidx
                                        isCollide = true
                                        break
                                    else
                                        if self.passedBbsThisBullet[v] == nil then
                                            passableBbs[#passableBbs+1] = v
                                        end
                                    end

                                end
                            end
                        end
                    end
                    if isCollide == true then
                        break
                    
                    end
                end
            end



            -------------------------------------------------------------------
            --old version


            -- local function calcY(rowIdx)
            --     assert(rowIdx > 0, "rowIdx == %d", rowIdx)
            --     local innerHeight = Bubble.radius + (rowIdx - 1) *2 * Bubble.intervalY
            --     return GameScene.topBoundary - innerHeight
            -- end

            -- for rowidx = #self.levelbubbles, 1, -1 do

            --     local row = self.levelbubbles[rowidx]
            --     if  type(row) == "table" then

            --         local ymid = calcY(rowidx) + self.mapbbOffsetY
            --         local ybottom = ymid - Bubble.intervalY
            --         local ytop = ymid + Bubble.intervalY


            --         if dest.y + Bubble.radius > ybottom and dest.y - Bubble.radius < ytop then


            --             for colidx = 1, s_colCnt, 1 do
            --                 local v = row[colidx]
            --                 if type(v) == "table" then

            --                     if v.itype then
            --                         local pos = {}

            --                         --lkj note:这里换做对应行列的方式来取位置，是因为boss发射泡泡的时候在发射瞬间，已经决定了泡泡的行列归属，但是泡泡的实际没有到达最终位置，这样子弹可能检测不到碰撞，而射到这个实际已经存在泡泡的位置了
            --                         --pos.x, pos.y = v.view:getPosition()
            --                         --replace with below
            --                         pos.x, pos.y = GameScene.bb_pos(rowidx,colidx)

            --                         pos.y = pos.y + self.mapbbOffsetY
            --                         local distSQ = math.pow(pos.x - dest.x,2) + math.pow(pos.y - dest.y,2)

            --                         local tolerance = 40
            --                         if distSQ < Bubble.distSq - tolerance then

            --                             if v.passable == false or self.curbt.itype == _pp.bt_boom then
            --                                 self.bulletRun = false
            --                                 rowidx_collision = rowidx
            --                                 colidx_collision = colidx
            --                                 isCollide = true
            --                                 break
            --                             else
            --                                 if self.passedBbsThisBullet[v] == nil then
            --                                     passableBbs[#passableBbs+1] = v
            --                                 end
            --                             end

            --                         end
            --                     end
            --                 end
            --             end
            --             if isCollide == true then
            --                 break
            --             end
            --         end
            --     end
            -- end

            -------------------------------------------------------------------
            -------------------------------------------------------------------




            local rowidx_bt, colidx_bt, poskey

            if self.bulletRun == true then
                local leftwall = s_uiinfo.startbb.position.x
                local topwall = s_uiinfo.startbb.position.y + self.mapbbOffsetY
                if dest.y < topwall then
                    self.curbt.view:setPosition(dest)
                else
                    dest.y = topwall
                    rowidx_bt = 1
                    colidx_bt,dest.x,poskey = self:adjustToTopwall(dest.x - leftwall)
                    --直接粘到顶上
                    --self:bb_attachToMap(self.curbt,1,destCol, true,mt_dynamic)

                    self.bulletRun = false
                end

                --空气、金币等可穿过的泡泡
                for k,v in pairs(passableBbs)do
                    assert(self.passedBbsThisBullet[v] == nil)
                    self.passedBbsThisBullet[v] = true
                    self:bb_view_Explode(v, {_pp.scorespace})
                    --v.view:removeFromParent(true)
                end
                self:bbs_elimilateFromMap(passableBbs)

            end

            if self.bulletRun == false then
                --碰撞bb

                local conbb = nil

                -------------------------------------------------------------
                --粘上
                if isCollide == true then
                    conbb = self.levelbubbles[rowidx_collision][colidx_collision]
                    local cpos = {}
                    cpos.x,cpos.y = conbb.view:getPosition()

                    ----碰撞后的bullet位置取当前和下一帧的lerp值
                    local midpos = {x = 0, y = 0}
                    local lerp = 0.7
                    midpos.x = curpos.x * lerp + dest.x*(1-lerp)
                    midpos.y = curpos.y * lerp + dest.y*(1-lerp)
                    self.curbt.view:setPosition(midpos)

                    --最近位置的列表，后面对他进行排序，如果和已有位置冲突，则取下一个此近位置
                    local distTable = {}

                    --adjust curbt pos    onto   the collision bb
                    --d_print("collision: rowlidx="..rowidx_collision.." colidx == "..colidx_collision)

                    cpos.y = cpos.y + self.mapbbOffsetY
                    local relativeCurPos = cc.pSub(curpos,cpos)

                    for k,v in pairs(s_bbRoundPos) do
                        local distSQ = cc.pDistanceSQ(v,relativeCurPos)
                        distTable[#distTable +1] = {sq = distSQ, key = k}
                    end
                    --六个位置排序
                    local function findNearest(a,b)
                        if a.sq < b.sq then
                            return true
                        else
                            return false
                        end
                    end
                    table.sort(distTable, findNearest)
                    rowidx_bt, colidx_bt, poskey = self:calc_bulletToMap_row_col_poskey(self.curbt, rowidx_collision, colidx_collision, distTable)


                else --没有发生和bb的碰撞而停下来（触顶）
                --已经在前面一步粘到顶上
                end

                ------------------------------------------------------------
                --粘上后

                --被撞bb发生的逻辑
                if conbb then
                    if conbb.itype == _pp.bt_boss then
                        self:logic_bbHitBoss(conbb)
                        self.curbt.view:removeFromParent(true)
                        self.curbt = nil
                        self:generateBulletBB()
                        return
                    elseif conbb.itype == _pp.bt_key then
                        self:logic_bbHitKey(conbb)
                        local score = pp.scorebase
                        self:bb_view_Explode(self.curbt, {score, self.curbt})
                        self.curbt = nil
                        self:generateBulletBB()
                        return
                    end
                end

                --空气bb统计
                local vecPassedBbs = {}
                for k in pairs(self.passedBbsThisBullet)do
                    vecPassedBbs[#vecPassedBbs+1] = k
                end
                -- local function __d1()
                --     self:gm_bbs_Explode(vecPassedBbs, cpos.x, cpos.y)
                -- end
                -- --performWithDelay(self.view, __d1, 0)
                -- __d1()
                local passedNeedChkFds = self:graph_remove_bbs(vecPassedBbs)

                --子弹bb 进入map
                self:bb_attachToMap(self.curbt, rowidx_bt, colidx_bt, true, mt_dynamic)
                if isCollide then
                    self:bb_ani_shakeAround(rowidx_collision, colidx_collision, poskey)
                else
                    self:bb_ani_shakeAround(rowidx_bt, colidx_bt, poskey)
                end

                --checkfall，graph环境是空气bb删掉，子弹bb进入的
                self:fields_CheckFall(passedNeedChkFds, self.curbt.view:getPosition())


                --运动bullet bb 发生的逻辑
                if self.curbt.itype == _pp.bt_boom then
                    AudioEngine.playEffect(sound.boom)
                    self:ani_baozha(self.curbt)

                    local booms = {self.curbt}
                    local key_hit = nil
                    local boss_hit = nil
                    for k,v in ipairs(s_dirs)do
                        local b = self:getBB_around_bb(self.curbt.row,self.curbt.col,v)
                        if b then
                            if b.itype == _pp.bt_key then
                                key_hit = b
                                booms[#booms+1] = b
                            elseif b.itype == _pp.bt_boss then
                                boss_hit = b
                            else
                                booms[#booms+1] = b
                            end
                        end
                    end

                    if key_hit then
                        self:logic_bbHitKey(key_hit)
                        local score = pp.scorebase
                        self:bb_view_Explode(self.curbt, {score, self.curbt})
                        self.curbt = nil
                        return
                    else
                        --delay process for optimize
                        --                local function __delay1(sender)
                        --                    self:gm_bbs_Explode(booms, curpos.x, curpos.y)
                        --                end
                        --                performWithDelay(self.view, __delay1, 0)

                        self:gm_bbs_Explode(booms, curpos.x, curpos.y)
                    end

                    if boss_hit then
                        self:logic_bbHitBoss(boss_hit)
                    end

                elseif self.curbt.itype == _pp.bt_fenji then
                    AudioEngine.playEffect(sound.fenji)

                    local fenjiRegion
                    if self.curbt.row%2 == 0 then
                        fenjiRegion = _pp.weapon_fenji_region_even[_userData.weaponLv_fenji]
                    else
                        fenjiRegion = _pp.weapon_fenji_region_odd[_userData.weaponLv_fenji]
                    end

                    local booms = {self.curbt}
                    local key_hit = nil
                    local boss_hit = nil
                    for k,v in pairs(fenjiRegion)do
                        local row = self.curbt.row + v[1]
                        local col = self.curbt.col + v[2]
                        if row >= 1 and row <= #self.levelbubbles and col >= 1 and col <= s_colCnt then
                            local b = self.levelbubbles[row][col]
                            if b and b ~= 0 then
                                if b.itype == _pp.bt_key then
                                    key_hit = b
                                    booms[#booms+1] = b
                                elseif b.itype == _pp.bt_boss then
                                    boss_hit = b
                                else
                                    booms[#booms+1] = b
                                end

                            end
                        end
                    end

                     --play ani
                    self:weapon_fenji_ani(self.curbt.view:getPosition())
    


                    if key_hit then
                        self:logic_bbHitKey(key_hit)
                        local score = pp.scorebase
                        self:bb_view_Explode(self.curbt, {score, self.curbt})
                        self.curbt = nil
                        return

                    else
                        --delay process for optimize
                        local function __delay1(sender)
                            self:gm_bbs_Explode(booms, curpos.x, curpos.y)
                            self.bGmProcessDelayCnt = self.bGmProcessDelayCnt - 1
                            gameData.status = _pp.gamestate_playing
                        end
                        performWithDelay(self.view, __delay1, 0)
                        self.bGmProcessDelayCnt = self.bGmProcessDelayCnt + 1

                        --                        self:gm_bbs_Explode(booms, curpos.x, curpos.y)
                    end

                    if boss_hit then
                        self:logic_bbHitBoss(boss_hit)
                    end

                else
                    --普通颜色球
                    self:bb_checkFieldExplode(self.curbt, {})
                end

                self.bGmProcessing = true

                -- gen next bb
                self.curbt = nil
                self:generateBulletBB()
            end

        end

    end


    --min interval collision detect
    local leftDelta = delta
    while leftDelta>0 do
        local thisDelta
        if leftDelta > s_maxDelta then
            thisDelta = s_maxDelta
        else
            thisDelta = leftDelta
        end
        if self.bulletRun == true then
            motionUpdate(thisDelta)
            leftDelta = leftDelta - thisDelta
        else
            break
        end
    end


    --guide - by mapOffset
    if DEF_GUIDE then
        self:guide_OnMapOffsetBelow_checkNext()
    end
end

function GameScene:comb_up(x,y)
    self.bCombing = true
    self.comb_time = 0

    if self.comb_cnt < _pp.comb_maxCnt then
        self.comb_cnt = self.comb_cnt + 1
    end

    if self.comb_cnt >= 2 then
        local combview = ccui.ImageView:create(_pp.comb_image[self.comb_cnt], ccui.TextureResType.localType)

        combview:setPosition((_pp.center.x + x)*0.5, y - 100 + self.mapbbOffsetY*0.88)
        self.widget:addChild(combview)
        combview:setLocalZOrder(pp.z_comb)
        uiEffect.scaleInUp(combview, _pp.center.y*0.12)

        self.bNeedPlayCombUpSound = true
    end
    --boss
    if self.boss then
        self.boss:xpRollback(self.comb_cnt)
    end
end

function GameScene:cleanMapGap()
    for rowidx = #self.levelbubbles, 1, -1 do
        local row  = self.levelbubbles[rowidx]
        local bGap = true
        for k,v in pairs(row)do
            if v ~= 0 then
                bGap = false
                break
            end
        end
        if bGap == true then
            self.levelbubbles[rowidx] = nil
        else
            break
        end
    end
    --    if self.levelbubbles[1] == nil and gameData.status ~= pp.gamestate_win then
    --        gameData.status = pp.gamestate_win
    --        self:onGameWin(2)
    --    end
end

function GameScene:hitLogic_boom(boom)
    local score = pp.scorebase
    self:bb_view_Explode(self.curbt, {score, self.curbt})
    self.curbt = nil

    self.levelbubbles[boom.row][boom.col] = 0
    local booms = {boom}
    for k,v in ipairs(s_dirs)do
        local b = self:getBB_around_bb(boom.row,boom.col,v)
        if b then
            if b.itype == pp.bt_key then

            else
                booms[#booms+1] = b
                self.levelbubbles[b.row][b.col] = 0
            end

        end
    end

    for k,v in pairs(booms)do
        uiEffect.boom(v.view)
    end

    return booms
end

function GameScene:bb_addToMap(bb)
    self.levelbubbles[bb.row] = self.levelbubbles[bb.row] or {0,0,0,0,0,0,0,0,0} 
    assert(self.levelbubbles[bb.row][bb.col] == nil or self.levelbubbles[bb.row][bb.col] == 0)
    self.levelbubbles[bb.row][bb.col] = bb
    self:bb_increComTypeCnt(bb)
end

function GameScene:bb_elimilateFromMap(bb)
    local mapbbs = self.levelbubbles
    if mapbbs[bb.row] and mapbbs[bb.row][bb.col] ~= 0 then
        mapbbs[bb.row][bb.col] = 0
        self:bb_decreComTypeCnt(bb)
    end
end

function GameScene:bbs_elimilateFromMap(bbs)
    local mapbbs = self.levelbubbles
    for k,v in pairs(bbs)do
        if mapbbs[v.row] and mapbbs[v.row][v.col] ~= 0 then
            mapbbs[v.row][v.col] = 0
            self:bb_decreComTypeCnt(v)
        end
    end
end

function GameScene:logic_bbHitKey(key)
    AudioEngine.playEffect(sound.hitKey)

    gameData.status = pp.gamestate_win

    local score = pp.scorebase
    -- self:bb_view_Explode(self.curbt, {score, self.curbt})
    -- self.curbt = nil

    --self:bb_elimilateFromMap(key)
    local keyaction = cc.Spawn:create(
        cc.ScaleBy:create(0.4, 6),
        cc.FadeOut:create(0.4)
    )
    key.view:runAction(
        cc.Sequence:create(
            keyaction,
            cc.RemoveSelf:create()
        )
    )

    local delay = 0
    for rowidx = #self.levelbubbles, 1, -1 do
        local row = self.levelbubbles[rowidx]
        for colidx = 1, s_colCnt, 1 do
            local bb = row[colidx]
            if bb ~= 0 --[[and bb.itype >= pp.bt_comStart and bb.itype <= pp.bt_comEnd]] then
                self:bb_elimilateFromMap(bb)

                delay = delay + 0.05
                local function bbExplode(sender, table)
                    self:bb_view_Explode(table[2], table)
                end
                bb.view:runAction(
                    cc.Sequence:create(
                        cc.DelayTime:create(delay),
                        cc.CallFunc:create(bbExplode, {score, bb})
                    )
                )
            end
        end

    end

    --win了后还应该做的，这里不做了:cleanMapGap,  bExplode

    -- local function popWinPanel(sender) self:onGameWin() end
    -- self.view:runAction(
    --     cc.Sequence:create(
    --         cc.DelayTime:create(delay + 0.5),
    --     cc.CallFunc:create(popWinPanel)
    --     ))
    self:onGameWin(delay+0.5)
end

function GameScene:boss_die()
    gameData.status = pp.gamestate_win

    local score = pp.scorebase
    -- self:bb_view_Explode(self.curbt, {score, self.curbt})
    -- self.curbt = nil

    --self:bb_elimilateFromMap(key)
    local action = cc.Spawn:create(
        cc.ScaleBy:create(0.4, 6),
        cc.FadeOut:create(0.4)
    )
    self.boss.view:runAction(
        cc.Sequence:create(
            action,
            cc.RemoveSelf:create()
        )
    )

    local delay = 0
    for rowidx = #self.levelbubbles, 1, -1 do
        local row = self.levelbubbles[rowidx]
        for colidx = 1, s_colCnt, 1 do
            local bb = row[colidx]
            if bb ~= 0 --[[and bb.itype >= pp.bt_comStart and bb.itype <= pp.bt_comEnd]] then
                self:bb_elimilateFromMap(bb)

                delay = delay + 0.05
                local function bbExplode(sender, table)
                    self:bb_view_Explode(table[2], table)
                end
                bb.view:runAction(
                    cc.Sequence:create(
                        cc.DelayTime:create(delay),
                        cc.CallFunc:create(bbExplode, {score, bb})
                    )
                )
            end
        end

    end

    --win了后还应该做的，这里不做了:cleanMapGap,  bExplode
    self:onGameWin(delay+0.5)
end

--判定游戏结束时，禁止使用道具
function GameScene:preventUserOperation()
    self.bt_yuheng:setEnabled(false)
    self.bt_fenji:setEnabled(false)
end

function GameScene:onGameWin(delay)
    local bOdd = (gameData.level%2 == 1)  --lkj see: update 2015/1/20
    if userData.fulllives ~= pp.lives_fullcnt_high and bOdd and not self.alreadyPopChangwanGift then
        WarningPanel.create(self,"Pay_ChangwanGift")
        self.alreadyPopChangwanGift = true
    else
        self:game_win(delay)
    end
end

function GameScene:game_win(delay)
    self:preventUserOperation()
    local function func(sender)
        --may occur bug(star info in level file, min level is one star, but there maybe get ZERO star),so add:
        if gameData.curStars == 0 then
            self:score_setToOneStar()
        end

        gameUtil.handleProcess_gameWin()
        self.ui_fnt_coin:setString(string.format("%d",userData.coin))

        self.resultPanel:show()
        uiEffect.bounceIn(self.resultPanel.view)
        self:base_onOpenWin(self.resultPanel)

        -- AudioEngine.stopAllEffects()
        AudioEngine.playEffect(sound.success)
        AudioEngine.stopMusic()

        gameUtil.sendGameStat(et.Level_Success, gameData.level, gameData.fuhuoTimes)
    end

    performWithDelay(self.view, func, delay)
    -- end
end

function GameScene:onGameFail()
    gameData.status = _pp.gamestate_fail
    -- if gameData.fuhuoTimes == 0 then
    --     WarningPanel.create(self, "GameScene_freeFuhuo")
    -- elseif gameData.fuhuoTimes == 1 then
    --     local bTrap = false
    --     for k,v in ipairs(_pp.spe_doubleFuhuoTrapTimes) do
    --         if userData.spe_doubleFuhuoTimes == v then
    --             bTrap = true
    --             break
    --         end 
    --     end
    --     if bTrap then
    --         WarningPanel.create(self, "Pay_game_Libao_Fuhuo")
    --     else
    --         WarningPanel.create(self, "GameScene_freeFuhuo")
    --     end
    -- else
    --     WarningPanel.create(self, "Pay_game_FuHuo")
    -- end

    local bOdd = (gameData.level%2 == 1)  --lkj see: update 2015/1/20
    if userData.fulllives ~= pp.lives_fullcnt_high and bOdd and not self.alreadyPopChangwanGift then
        WarningPanel.create(self,"Pay_ChangwanGift")
        self.alreadyPopChangwanGift = true
    else 
        if userData.spe_freeFuhuoLeft == 0  then
            if userData.spe_bought_doubleFuhuoLibao < 3 then
                WarningPanel.create(self, "Pay_game_Libao_Fuhuo")
            else
                WarningPanel.create(self, "Pay_game_Libao_Fuhuo2")
            end
        else
            self:wrapper_WarningPanel_create_freeFuhuo()
        end
    end
    
    self:game_pause()
end

function GameScene:wrapper_WarningPanel_create_freeFuhuo()
    local panel = WarningPanel.create(self, "GameScene_freeFuhuo")
    --lkj spe:不告诉免费复活的剩余次数。。。
    -- local leftcntfnt = cc.LabelBMFont:create(string.format("%d", userData.spe_freeFuhuoLeft), pp.fnt_number_yellow)
    -- leftcntfnt:setPosition(120,11)
    -- leftcntfnt:setScale(1.3)
    -- panel.view:addChild(leftcntfnt, 100)
    return panel
end

function GameScene:onGameFuhuo()
    -- body
    gameData.fuhuoTimes = gameData.fuhuoTimes + 1

    gameUtil.sendGameStat(et.Level_Fuhuo, gameData.level, gameData.fuhuoTimes)

    if gameData.fuhuoTimes == 2 then
        userData.spe_doubleFuhuoTimes = userData.spe_doubleFuhuoTimes + 1
        gameUtil.flushUserRecord()
    end

    gameData.status = _pp.gamestate_fuhuoing
    self:game_resume_callback()
    AudioEngine.playEffect(sound.fuhuo)

    self.fuhuo_fallspeed_rate =  _pp.fuhuoSpeedRate[gameData.fuhuoTimes+1] or _pp.fuhuoSpeedRate[#_pp.fuhuoSpeedRate]
end

function GameScene:game_fail()
    gameData.status = pp.gamestate_fail
    gameUtil.handleProcess_gameFail()
    self.resultPanel:show()
    uiEffect.bounceIn(self.resultPanel.view)
    self:base_onOpenWin(self.resultPanel)

    AudioEngine.playEffect(sound.fail)
    AudioEngine.stopMusic()

    gameUtil.sendGameStat(et.Level_Fail, gameData.level, gameData.fuhuoTimes)
end

function GameScene.bb_pos(row, col)
    local startpos = s_uiinfo.startbb.position
    x = startpos.x + (col - 1)*2*Bubble.radius +  (1- row%2) * Bubble.radius
    y = startpos.y - (row - 1)*2*Bubble.intervalY
    return x,y
end

function GameScene:bb_increComTypeCnt(bb)
    local ty = bb.itype
    local tytbl = self.bbCntEachType
    if ty >= pp.bt_comStart and ty <= pp.bt_comEnd then
        tytbl[bb.itype] = tytbl[bb.itype] + 1
    end
end

function GameScene:bb_decreComTypeCnt(bb)
    local ty = bb.itype
    local tytbl = self.bbCntEachType
    if ty >= pp.bt_comStart and ty <= pp.bt_comEnd then
        tytbl[bb.itype] = tytbl[bb.itype] - 1
    end
end

function GameScene:bb_attachToMap(bb, row, col, needgraph, motionType, poskey)
    if col == 0 then
        d_print("error: col == 0")
    end

    bb.row = row
    bb.col = col
    local x, y = GameScene.bb_pos(row, col)

    if motionType and motionType == mt_dynamic then
        local bbx, bby = bb.view:getPosition()
        bb.view:removeFromParent(true)

        bb:newView()
        self.bbLayer:addChild(bb.view)
        bb.view:setLocalZOrder(pp.z_mapbb)
        bb.view:setPosition(bbx, bby - self.mapbbOffsetY)

        AudioEngine.playEffect(sound.bbStick)

        local dist_cur_dest = {x=0,y=0}
        dist_cur_dest.x = x - bbx
        dist_cur_dest.y = y - bby - self.mapbbOffsetY
        local move_vec = cc.pNormalize(dist_cur_dest)

        local shortBounce = 0.12*Bubble.radius
        local dist = cc.pMul(move_vec, shortBounce)



        --test don't use bt bounceback, use simply move
        -- local back = cc.EaseSineOut:create(cc.MoveBy:create(0.09, dist))
        -- local bounce = back:reverse()
        bb.view:runAction(cc.Sequence:create(
            cc.MoveTo:create(0.05, cc.p(x, y))--,
        -- bounce,
        -- back
        ))


        --eft
        local fadein = cc.FadeIn:create(0.02)
        local fadeout = cc.FadeOut:create(0.2)
        local blink = cc.Sequence:create(fadein, fadeout, cc.RemoveSelf:create())

        local blinkImg = ccui.ImageView:create("bubbles/guangqiu.png", ccui.TextureResType.localType)
        -- blinkImg:setOpacity(0)
        --self.widget:addChild(blinkImg,7000)
        --blinkImg:setPosition(cc.p(300,300))

        blinkImg:setAnchorPoint(cc.p(0,0))
        blinkImg:setPosition(cc.p(-6,-6))
        bb.view:addChild(blinkImg)
        blinkImg:runAction(blink)

        -- elseif motionType == mt_dynamic then
        --    bb.view:runAction(cc.MoveTo:create(0.07, cc.p(x, y)))
        -- end
    else
        bb.view:setPosition(x, y)
    end

    self:bb_addToMap(bb)

    --update graph
    if needgraph == true then
        self:graph_make(bb, s_dirs)
    end
    --[[dump graph
    Field.dumpGraph(self.levelbubbles)
    --]]
end


GameScene.shakeAroundDef = {
    --             mf   mr  rf
    --
    --          ml    m    r
    --
    --        lf    l    center
    [dirRB] = {l = dirL, m = dirLT, r = dirRT, lf = dirL, ml = dirLT, mf = dirLT, mr = dirLT, rf = dirRT,
        l_vec = dirL_vector, ml_vec = {x = -s_COS30, y = 0.5}, m_vec = dirLT_vector, mr_vec = {x = 0, y = 1}, r_vec = dirRT_vector },

    --        lf    ml   mf
    --
    --          l    m    mr
    --
    --            c    r    rf
    [dirLB] = {l = dirLT, m = dirRT, r = dirR, lf = dirLT, ml = dirRT, mf = dirRT, mr = dirRT, rf = dirR,
        l_vec = dirLT_vector, ml_vec = {x = 0,y = 1}, m_vec = dirRT_vector, mr_vec = {x = s_COS30, y = 0.5}, r_vec = dirR_vector},

    --                   lf
    --
    --                l     ml
    --
    --             c     m     mf
    --
    --                r     mr
    --
    --                   rf
    [dirL] = {l = dirRT, m = dirR, r = dirRB, lf = dirRT, ml = dirR, mf = dirR, mr = dirR, rf = dirRB,
        l_vec = dirRT_vector, ml_vec = {x = s_COS30, y = 0.5}, m_vec = dirR_vector, mr_vec = {x = s_COS30, y = -0.5}, r_vec = dirRB_vector},

    --             c    l    lf
    --
    --           r    m    ml
    --
    --         rf   mr   mf
    [dirLT] = {l = dirR, m = dirRB, r = dirLB, lf = dirR, ml = dirRB, mf = dirRB, mr = dirRB, rf = dirLB,
        l_vec = dirR_vector, ml_vec = {x = s_COS30, y = -0.5}, m_vec = dirRB_vector, mr_vec = {x = 0, y = -1}, r_vec = dirLB_vector},

    --        rf    r    c
    --
    --          mr    m    l
    --
    --            mf    ml    lf
    [dirRT] = {l = dirRB, m = dirLB, r = dirL, lf = dirRB, ml = dirLB, mf = dirLB, mr = dirLB, rf = dirL,
        l_vec = dirRB_vector, ml_vec = {x = 0, y = -1}, m_vec = dirLB_vector, mr_vec = {x = -s_COS30, y = -0.5}, r_vec = dirL_vector},

    --                   rf
    --
    --                mr     r
    --
    --             mf     m     c
    --
    --                ml     l
    --
    --                   lf
    [dirR] = {l = dirRB, m = dirL, r = dirLT, lf = dirLB, ml = dirL, mf = dirL, mr = dirL, rf = dirLT,
        l_vec = dirLB_vector, ml_vec = {x = -s_COS30, y = -0.5}, m_vec = dirL_vector, mr_vec = {x = -s_COS30, y = 0.5}, r_vec = dirLT_vector},
}


function GameScene:bb_ani_shakeAround(row, col, poskey)
    local shakeTime = 0.08
    local shortBounce = 0.1*Bubble.radius
    local longBounce = 0.2*Bubble.radius
    --             mf   mr  rf
    --
    --          ml    m    r
    --
    --        lf    l    center
    local l,m,r,lf,ml,mf,mr,rf
    local bbs = self.levelbubbles
    local dirs = GameScene.shakeAroundDef[poskey]

    local center = bbs[row][col]


    if center ~= 0 then
        local c_dist = cc.pMul(dirs.m_vec, shortBounce)
        local c_bounce = cc.EaseSineOut:create(cc.MoveBy:create(shakeTime, c_dist))
        local c_back = c_bounce:reverse()
        center.view:runAction(cc.Sequence:create(c_bounce, c_back))
    end

    local l_row, l_col = self:getBB_around_rc(row,col,dirs.l)
    local m_row, m_col = self:getBB_around_rc(row,col,dirs.m)
    local r_row, r_col = self:getBB_around_rc(row,col,dirs.r)
    l = self:getBB_byRowCol(l_row, l_col)
    m = self:getBB_byRowCol(m_row, m_col)
    r = self:getBB_byRowCol(r_row, r_col)

    if l ~= nil then
        lf = self:getBB_around_bb(l_row,l_col,dirs.lf)
        if lf == nil then
            local l_dist = cc.pMul(dirs.l_vec, longBounce)

            local l_bounce = cc.EaseSineOut:create(cc.MoveBy:create(shakeTime, l_dist))
            local l_back = l_bounce:reverse()
            l.view:runAction(cc.Sequence:create(l_bounce, l_back))
        else
            local l_dist = cc.pMul(dirs.l_vec, shortBounce)
            local lf_dist = cc.pMul(dirs.l_vec, longBounce)

            local l_bounce = cc.EaseSineOut:create(cc.MoveBy:create(shakeTime, l_dist))
            local l_back = l_bounce:reverse()
            l.view:runAction(cc.Sequence:create(l_bounce, l_back))

            local lf_bounce = cc.EaseSineOut:create(cc.MoveBy:create(shakeTime, lf_dist))
            local lf_back = lf_bounce:reverse()
            lf.view:runAction(cc.Sequence:create(lf_bounce, lf_back))

        end

    end

    if m ~= nil then
        mf = self:getBB_around_bb(m_row, m_col, dirs.mf)
        if mf == nil then
            local m_dist = cc.pMul(dirs.m_vec, longBounce)
            
            local m_bounce = cc.EaseSineOut:create(cc.MoveBy:create(shakeTime, m_dist))
            local m_back = m_bounce:reverse()
            m.view:runAction(cc.Sequence:create(m_bounce, m_back))
        else
            local m_dist = cc.pMul(dirs.m_vec, shortBounce)
            local mf_dist = cc.pMul(dirs.m_vec, longBounce)

            local m_bounce = cc.EaseSineOut:create(cc.MoveBy:create(shakeTime, m_dist))
            local m_back = m_bounce:reverse()
            m.view:runAction(cc.Sequence:create(m_bounce, m_back))

            local mf_bounce = cc.EaseSineOut:create(cc.MoveBy:create(shakeTime, mf_dist))
            local mf_back = mf_bounce:reverse()
            mf.view:runAction(cc.Sequence:create(mf_bounce, mf_back))
        end
    end

    if r ~= nil then
        rf = self:getBB_around_bb(r_row, r_col, dirs.rf)
        if rf == nil then
            local r_dist = cc.pMul(dirs.r_vec, longBounce)

            local r_bounce = cc.EaseSineOut:create(cc.MoveBy:create(shakeTime, r_dist))
            local r_back = r_bounce:reverse()
            r.view:runAction(cc.Sequence:create(r_bounce, r_back))
        else
            local r_dist = cc.pMul(dirs.r_vec, shortBounce)
            local rf_dist = cc.pMul(dirs.r_vec, longBounce)

            local r_bounce = cc.EaseSineOut:create(cc.MoveBy:create(shakeTime, r_dist))
            local r_back = r_bounce:reverse()
            r.view:runAction(cc.Sequence:create(r_bounce, r_back))

            local rf_bounce = cc.EaseSineOut:create(cc.MoveBy:create(shakeTime, rf_dist))
            local rf_back = rf_bounce:reverse()
            rf.view:runAction(cc.Sequence:create(rf_bounce, rf_back))
        end
    end

    if l and m then
        ml = self:getBB_around_bb(l_row,l_col, dirs.ml)
        if ml then
            local ml_dist = cc.pMul(dirs.ml_vec, longBounce)

            local ml_bounce = cc.EaseSineOut:create(cc.MoveBy:create(shakeTime, ml_dist))
            local ml_back = ml_bounce:reverse()
            ml.view:runAction(cc.Sequence:create(ml_bounce, ml_back))
        end
    end

    if r and m then
        mr = self:getBB_around_bb(r_row,r_col, dirs.mr)
        if mr then
            local mr_dist = cc.pMul(dirs.mr_vec, longBounce)

            local mr_bounce = cc.EaseSineOut:create(cc.MoveBy:create(shakeTime, mr_dist))
            local mr_back = mr_bounce:reverse()
            mr.view:runAction(cc.Sequence:create(mr_bounce, mr_back))
        end
    end

end

function GameScene:calc_bulletToMap_row_col_poskey(bullet, rowidx_collision, colidx_collision, distTable)
    local poskey
    local rowidx_bt, colidx_bt
    for k,v in ipairs(distTable) do

        poskey = v.key
        rowidx_bt, colidx_bt = self:getBB_around_rc(rowidx_collision, colidx_collision, poskey)
        if rowidx_bt ~= 0 and colidx_bt ~=  0 then
            --map not exist row
            if self.levelbubbles[rowidx_bt] == nil then
                self.levelbubbles[rowidx_bt] = {0,0,0,0,0,0,0,0,0}           
                --d_print("bullet on! row, col, key == "..rowidx_bt.." "..colidx_bt.." "..poskey)

                return rowidx_bt, colidx_bt, poskey
            else    --map exist row
                local target = self.levelbubbles[rowidx_bt][colidx_bt]
                if  target == 0 then   -- row not exist bb              
                    --d_print("bullet on! row, col, key == "..rowidx_bt.." "..colidx_bt.." "..poskey)
                    return rowidx_bt, colidx_bt, poskey

                elseif target.passable == true then
                    --发生这种情况是由于卡顿或者泡泡bullet射速比较快，在运行中跳过了该泡泡的检测范围，而直接射到了collision bb的位置
                    d_print("passable!! attach !!!!!  collision row,col == "..rowidx_collision..","..colidx_collision)
                    assert(self.passedBbsThisBullet[target] == nil)
                    self.passedBbsThisBullet[target] = true
                    self:bb_view_Explode(target, {pp.scorespace})
                    self:bb_elimilateFromMap(target)
                    return rowidx_bt, colidx_bt, poskey
                end
            end
        end

        -- loop to next, until find a slot
    end

    --not find a slot.....
    d_print("collision row,col == "..rowidx_collision..","..colidx_collision)
    assert(nil,"not find a slot, rowidx:"..rowidx_bt.." colidx:"..colidx_bt)

end

--           lt o       o rt
--
--        l o       o       o r
--
--           lb o       o rb

local s_around_idxTbl_even = {
    [dirLT] = {-1,0},
    [dirRT] = {-1,1},
    [dirR] = {0,1},
    [dirRB] = {1,1},
    [dirLB] = {1,0},
    [dirL] = {0,-1},
}
local s_around_idxTbl_odd = {
    [dirLT] = {-1,-1},
    [dirRT] = {-1,0},
    [dirR] = {0,1},
    [dirRB] = {1,0},
    [dirLB] = {1,-1},
    [dirL] = {0,-1},
}

function GameScene:getBB_around_rc(centerR, centerC, poskey)
    local idxTbl_even = s_around_idxTbl_even
    local idxTbl_odd = s_around_idxTbl_odd
    local idxTbl = nil
    if centerR%2 == 1 then
        idxTbl = idxTbl_odd
    else
        idxTbl = idxTbl_even
    end

    local retR = centerR + idxTbl[poskey][1]
    local retC = centerC + idxTbl[poskey][2]

    if retR < 1 then retR = 0 end
    if retC < 1 or retC > s_colCnt then retC = 0 end
    return retR,retC
end

function GameScene:getBB_around_bb(centerR, centerC, poskey)
    local idxTbl_even = s_around_idxTbl_even
    local idxTbl_odd = s_around_idxTbl_odd
    local idxTbl = nil
    if centerR%2 == 1 then
        idxTbl = idxTbl_odd
    else
        idxTbl = idxTbl_even
    end

    local retR = centerR + idxTbl[poskey][1]
    local retC = centerC + idxTbl[poskey][2]

    return self:getBB_byRowCol(retR, retC)
end


function GameScene:getBB_byRowCol(row, col)
    local bbs = self.levelbubbles
    if bbs[row] and bbs[row][col]  and bbs[row][col] ~= 0 then
        return bbs[row][col]
    else
        return nil
    end
end

function GameScene:onGameViewTouched(location)
    if gameData.status ~= pp.gamestate_playing and
        gameData.status ~= pp.gamestate_weaponing
     then
        return
    end

    assert(self.bGmProcessDelayCnt >= 0)
    if self.curBtReady == false or self.bGmProcessDelayCnt > 0 then
        return
    end

    self.bulletRun = true
    self.passedBbsThisBullet = {}

    local startpt = {}
    startpt.x, startpt.y = self.curbt.view:getPosition()

    self.bulletDir = cc.pSub(location, startpt)
    self.bulletDir = cc.pNormalize(self.bulletDir)

    self.curBtReady = false

    --rot canon
    local rotRadian = math.atan(self.bulletDir.x / self.bulletDir.y) / math.pi * 180.0
    self.cannon:runAction(cc.RotateTo:create(0.05, rotRadian))


    AudioEngine.playEffect(sound.shootBullet)
    --
    --    s.view:stopAllActions()
    --    s.view:runAction(cc.MoveTo:create(1, cc.p(location.x, location.y)))
    --    local posX, posY = s.view:getPosition()
    --    local o = location.x - posX
    --    local a = location.y - posY
    --    local at = math.atan(o / a) / math.pi * 180.0
    --
    --    if a < 0 then
    --        if o < 0 then
    --            at = 180 + math.abs(at)
    --        else
    --            at = 180 - math.abs(at)
    --        end
    --    end
    --    s.view:runAction(cc.RotateTo:create(1, at))
end

function GameScene:coin_Raise(view, val)
    local x,y = view:getPosition()

    self:data_coinRaise(val)

    local scorestring = string.format("+%d", val)
    local fnt = cc.LabelBMFont:create(scorestring,  pp.fnt_number_yellow)
    fnt:setScale(1.5)
    fnt:setPosition(x,y + self.mapbbOffsetY)
    self.widget:addChild(fnt)
    fnt:setLocalZOrder(pp.z_epl_coin)
    fnt:runAction(
        cc.Sequence:create(
            cc.Spawn:create(
                cc.Sequence:create(cc.ScaleTo:create(0.3, 1.1),cc.ScaleTo:create(0.3, 0.6)),
                cc.FadeOut:create(1),
                cc.MoveBy:create(1.5, cc.p(0, Bubble.radius))
            ),

            cc.RemoveSelf:create()
        ))
end

function GameScene:ani_baozha(bb)
    local x,y = bb.view:getPosition()
    return self:ani_baozha_pos(x,y)
end

function GameScene:ani_baozha_pos(x,y)
    ccs.ArmatureDataManager:getInstance():removeArmatureFileInfo("ani/baozha/baozha.ExportJson")
    ccs.ArmatureDataManager:getInstance():addArmatureFileInfo("ani/baozha/baozha.ExportJson")
    local bzView = ccs.Armature:create("baozha")
    bzView:getAnimation():playWithIndex(0)
    self.widget:addChild(bzView, _pp.z_epl_ani)
    bzView:setPosition(x,y + self.mapbbOffsetY)
    return bzView
end

function GameScene:bb_view_Explode(bb, table)
    local _pp = pp

    local x,y = bb.view:getPosition()

    --类型判断
    if bb.itype == _pp.bt_coin then
        AudioEngine.playEffect(sound.hitCoin)
        self:coin_Raise(bb.view, gameData.leveldata.coin_val)
        bb.view:removeFromParent(true)
    elseif bb.itype == _pp.bt_boom then
        -- uiEffect.boom(bb.view)
        bb.view:removeFromParent(true)
        -- local bzView = uiAnimation.createAutoRelease("boom", false, 0.42)
        -- self.widget:addChild(bzView, _pp.z_epl_ani)
        -- bzView:setScale(1.4)
        -- bzView:setPosition(x,y + self.mapbbOffsetY)
    else
        bb.view:removeFromParent(true)
    end

    local bzView = uiAnimation.createAutoRelease("bz", false, 0.42)
    self.widget:addChild(bzView, _pp.z_epl_ani)
    bzView:setScale(0.8)
    bzView:setPosition(x,y + self.mapbbOffsetY)

    --------------------------------------------

    --加分
    --data show
    self:score_Raise(table[1])

    --ui
    local scorestring = string.format("%d", table[1])
    local scoreFnt = cc.LabelBMFont:create(scorestring,  pp.fnt_number_white)
    scoreFnt:setScale(0.1)
    scoreFnt:setPosition(x,y + self.mapbbOffsetY)
    self.widget:addChild(scoreFnt)
    scoreFnt:setLocalZOrder(pp.z_epl_score)
    scoreFnt:runAction(
        cc.Sequence:create(
            cc.Spawn:create(
                cc.Sequence:create(cc.ScaleTo:create(0.3, 0.7),cc.ScaleTo:create(0.3, 0.4)),
                cc.FadeOut:create(1.7),
                cc.MoveBy:create(1.7, cc.p(0, Bubble.radius))
            ),

            cc.RemoveSelf:create()
        ))



    AudioEngine.playEffect(sound.bbDel)
end

function GameScene:bbs_view_Explode(epl, centerx, centery)
    --从爆炸中心排序
    local function cmpNear(a,b)
        --        if IS_DEBUG then
        --            if (a.class.__cname ~= "Bubble" and a.class.__cname ~= "BubbleKey" and a.class.__cname ~= "BubbleBoom") or
        --                (b.class.__cname ~= "Bubble" and b.class.__cname ~= "BubbleKey" and b.class.__cname ~= "BubbleBoom") then
        --                assert(false, "cmpNear: not Bubble class")
        --            end
        --        end
        local ax,ay = a.view:getPosition()
        local orthodist_a = math.abs(ax - centerx) + math.abs(ay - centery)
        local bx,by = b.view:getPosition()
        local orthodist_b = math.abs(bx - centerx) + math.abs(by - centery)
        if orthodist_a < orthodist_b then
            return true
        else
            return false
        end
    end
    table.sort(epl, cmpNear)

    local function bbExplode(sender, table)
        self:bb_view_Explode(table[2], table)
    end


    local delay = 0
    local score = pp.scorebase
    local scorebaseidx = 0
    for k,v in ipairs(epl) do
        --泡泡消去
        scorebaseidx = scorebaseidx + 1
        if scorebaseidx > 3 then
            score = score + pp.scoreincre
        end
        v.view:runAction(
            cc.Sequence:create(
                cc.DelayTime:create(delay),
                cc.CallFunc:create(bbExplode, {score,v})
            )
        )

        delay = delay + 0.045
    end

    local function playCombSound()
        AudioEngine.playEffect(sound.comb[self.comb_cnt])
        d_print("play Comb : "..self.comb_cnt)
    end
    if self.bNeedPlayCombUpSound == true then
        performWithDelay(self.widget, playCombSound, delay+0.5)
        self.bNeedPlayCombUpSound = false
    end
end

function GameScene:gm_bbs_Explode(bbs, cx, cy)
    --lkj note:在进行graph操作前(如 graph_remove_bbs)，需要先update  levelbb的信息
    self:bbs_elimilateFromMap(bbs)
    local fields_needChk = self:graph_remove_bbs(bbs)
    local function bbsExplode(sender, table)
        --d_print("gm_bbs_explode: bbs_view_explode")
        for k,v in pairs(bbs) do
            --d_print("row:"..v.row.." col:"..v.col)
        end
        self:bbs_view_Explode(table[1], table[2], table[3])
    end

    self.view:runAction(
        cc.Sequence:create(
            cc.DelayTime:create(0.10) ,
            cc.CallFunc:create(bbsExplode, {bbs, cx, cy})
        ))


    local function __explode()
        self.bGmProcessDelayCnt = self.bGmProcessDelayCnt - 1
        self:fields_CheckFall(fields_needChk, cx, cy)
    end
    self.bGmProcessDelayCnt = self.bGmProcessDelayCnt + 1
    --performWithDelay(self.view, __explode, 0)

    __explode()
    --lkj debug:
    --self:fields_CheckFall(fields_needChk, cx, cy)
end

function GameScene:fields_CheckFall(fields, centerx, centery)
    local eplBbs = {}
    local notConFields = {}
    self:graph_checkFall(fields, notConFields)

    for k,v in pairs(notConFields)do
        for k1,v1 in pairs(k.elm)do
            eplBbs[#eplBbs+1] = v1
        end
        self:graph_remove_field(k)
    end

    --从map移除并且播放效果
    self:bbs_elimilateFromMap(eplBbs)
    local function bbsExplode(sender, table)
        --d_print("fields_CheckFall: bbs_view_explode")
        for k,v in pairs(eplBbs) do
            --d_print("row:"..v.row.." col:"..v.col)
        end
        self:bbs_view_Explode(table[1], table[2], table[3])
    end

    self.view:runAction(
        cc.Sequence:create(
            cc.DelayTime:create(0.10) ,
            cc.CallFunc:create(bbsExplode, {eplBbs, centerx, centery})
        ))
end

function GameScene:fields_Explode(eplFds, needChkFds, centerx, centery)  --bb is explode center
    local eplBbs = {}
    --local needChkFds = {}

    for k in pairs(eplFds)do
        for k1,v1 in pairs(k.elm)do
            eplBbs[#eplBbs+1] = v1
        end

        for k1 in pairs(k.adj)do
            needChkFds[k1] = true
        end
        self:graph_remove_field(k)
    end

    for k in pairs(eplFds)do
        needChkFds[k] = nil
    end

    --从map移除并且播放效果
    self:bbs_elimilateFromMap(eplBbs)
    local function bbsExplode(sender, table)
        self:bbs_view_Explode(table[1], table[2], table[3])
    end

    self.view:runAction(
        cc.Sequence:create(
            cc.DelayTime:create(0.15) ,
            cc.CallFunc:create(bbsExplode, {eplBbs, centerx, centery})
        ))

    self:fields_CheckFall(needChkFds, centerx, centery)
end

function GameScene:bb_checkFieldExplode(bb, needChkFds)
    local mapbbs = self.levelbubbles
    local _pp = pp
    local x,y = bb.view:getPosition()

    --预先保存周围泡泡信息
    local aroundbbs = {}
    for k,v in ipairs(s_dirs)do
        local b = self:getBB_around_bb(bb.row,bb.col,v)
        if b then
            aroundbbs[#aroundbbs+1] = b
        end
    end

    --检测爆破
    if bb.itype >= _pp.bt_comStart and bb.itype <= _pp.bt_comEnd then

        --local eplBbs = {}
        local eplFds = {}
        local adjFds = bb.field.adj
        local bEpl = false

        local mixedFds = {}

        for k in pairs(adjFds)do
            local elm1 = k.elm[1]
            local ty = elm1.itype

            if ty == _pp.bt_mixed then
                mixedFds[#mixedFds+1] = k

                for ka in pairs(k.adj)do
                    local _elm = ka.elm[1]
                    local _ty = _elm.itype
                    if _ty == _pp.bt_mixed then
                        --发现两个彩泡，周围不可能有有色区，只用消除那个彩泡
                        eplFds[ka] = true
                        eplFds[k] = true
                        bEpl = true
                        --找到可以合并的同色区，直接消除
                    elseif ka ~= bb.field and _ty == bb.field.elm[1].itype then
                        eplFds[ka] = true
                        eplFds[k] = true
                        bEpl = true
                    end
                end

            end
        end

        local bMixedEpl = false
        if #bb.field.elm >= 2 then
            if #mixedFds > 0 then
                bMixedEpl = true
            end
        elseif #mixedFds >= 2 then
            bMixedEpl = true
        end

        if bMixedEpl == true then
            for k,v in pairs(mixedFds)do
                eplFds[v] = true
                for ka in pairs(v.adj)do
                    eplFds[ka] = true
                end
            end
            bEpl = true
        end


        if bEpl == false then
            if #bb.field.elm >= 3 then
                bEpl = true
            end
        end

        if bEpl == true then

            eplFds[bb.field] = true
            self:fields_Explode(eplFds, needChkFds, x, y)

            self.bTripleUping = true
            self.tup_passed = 0

            self:comb_up(x,y)

        end


    elseif bb.itype == _pp.bt_mixed then

        --local eplBbs = {}
        local eplFds = {}
        local adjFds = bb.field.adj


        --判断是否爆炸
        local bEpl = false
        local sameitypeadj = {[1]=0,[2]=0,[3]=0,[4]=0,[5]=0,[6]=0,[7]=0} --临近区有同色区域，逻辑上是合并的，这里不需要做，直接判断可消除

        for k in pairs(adjFds)do
            local ty = k.elm[1].itype

            if (ty >= _pp.bt_comStart and ty <= _pp.bt_comEnd) then
                if #k.elm >= 2 then --连续两个同色
                    bEpl = true
                else --一个单色，周围是否有其它邻接彩球
                    for k1 in pairs(k.adj)do
                        if k1 ~= bb.field and k1.elm[1].itype == _pp.bt_mixed then
                            eplFds[k1] = true   --adj的adj中需要爆破的

                            --lkj discuss: 爆掉周围单色球
                            for kb in pairs(k1.adj)do
                                local tyb = kb.elm[1].itype
                                if tyb >= _pp.bt_comStart and tyb <= _pp.bt_comEnd then
                                    eplFds[kb] = true
                                end
                            end
                            --lkj discuss end

                            bEpl = true
                        end
                end
                end

                sameitypeadj[ty] = sameitypeadj[ty] + 1

            elseif ty == _pp.bt_mixed then

                local adj1 = k.adj
                for k1 in pairs(adj1)do
                    local _ty = k1.elm[1].itype
                    if _ty >= _pp.bt_comStart and _ty <= _pp.bt_comEnd then
                        eplFds[k1] = true
                        bEpl = true
                    elseif k1 ~= bb.field and _ty == _pp.bt_mixed then
                        eplFds[k1] = true
                        bEpl = true
                    end
                end
            end
        end

        if bEpl == false then
            for k,v in pairs(sameitypeadj)do
                if v > 1 then
                    bEpl = true
                end
            end
        end

        if bEpl == true then
            for k in pairs(adjFds)do
                local ty = k.elm[1].itype
                if (ty >= _pp.bt_comStart and ty <= _pp.bt_comEnd) or
                    ty == _pp.bt_mixed then
                    eplFds[k] = true
                else
                    needChkFds[k] = true
                end
            end

            eplFds[bb.field] = true
            self:fields_Explode(eplFds, needChkFds, x, y)

            self.bTripleUping = true
            self.tup_passed = 0

            self:comb_up(x,y)
        end

    end


    local colorChangeBbs = {}
    local targetTy

    local upCnt = 0
    local downCnt = 0
    local updownBbs = {}

    for k,v in pairs(aroundbbs)do
        if mapbbs[v.row][v.col] ~= 0 then
            if v.itype == _pp.bt_up then
                updownBbs[#updownBbs+1] = v
                upCnt = upCnt+1
            elseif v.itype == _pp.bt_down then
                updownBbs[#updownBbs+1] = v
                downCnt = downCnt+1

                --染色 (找到一个,后面找到的就忽略了)
            elseif v.itype >= _pp.bt_paintStart and v.itype <= _pp.bt_paintEnd and not targetTy then
                targetTy = v.itype - _pp.bt_paintOffset
                colorChangeBbs[#colorChangeBbs+1] = v
                for k1,v1 in ipairs(s_dirs)do
                    local b = self:getBB_around_bb(v.row,v.col,v1)
                    if b then
                        local ty = b.itype
                        if (ty >= _pp.bt_comStart and ty <= _pp.bt_comEnd) or
                            (ty >= _pp.bt_paintStart and ty <= _pp.bt_paintEnd) or
                            ty == _pp.bt_mixed
                        then

                            if ty ~= targetTy then
                                colorChangeBbs[#colorChangeBbs+1] = b
                            end
                        end
                    end
                end

                --问号
            elseif v.itype == _pp.bt_puzzle then
                colorChangeBbs[#colorChangeBbs+1] = v
            end
        end
    end

    local function __colorChangeFun()
        self:bbs_elimilateFromMap(colorChangeBbs)
        self:graph_remove_bbs(colorChangeBbs)
        for k,v in pairs(colorChangeBbs)do
            local ty = v.itype
            if (ty >= _pp.bt_comStart and ty <= _pp.bt_comEnd) or
                (ty >= _pp.bt_paintStart and ty <= _pp.bt_paintEnd) or
                ty == _pp.bt_mixed
            then
                v:changeToNewType(targetTy)
            elseif ty == _pp.bt_puzzle then
                local toTy = math.random(_pp.bt_comStart, _pp.bt_comEnd)
                v:changeToNewType(toTy)
            end
            self:bb_addToMap(v)
            self:graph_make(v, s_dirs)
        end
    end
    --optimize
    if #colorChangeBbs > 0 then
        performWithDelay(self.view, __colorChangeFun, 0)
    end

    local function __upFun()
        if upCnt == downCnt then
        --dont do updown
        elseif upCnt > downCnt then
            self.updown_state = UDS_up
            self.updown_passed = 0
        else
            self.updown_state = UDS_down
            self.updown_passed = 0
        end

        if mapbbs[bb.row][bb.col] ~= 0 then
            updownBbs[#updownBbs+1] = bb
        end
        self:gm_bbs_Explode(updownBbs, x, y)
    end
    if #updownBbs > 0 then
        -- performWithDelay(self.view, __upFun, 0) --这里可能由于下一帧mapbbs已经把bb删除了导致mapbbs[bb.row][bb.col]==nil,所以取消这部分性能优化
        __upFun()
    end
end

function GameScene:graph_checkFall(fields, notConFields)

    local function checkConnectEnd(fd, swept)
        if fd.isEnd == true then
            return true
        end

        swept[fd] = true    --先把自己加进去

        local adj = fd.adj
        for k,v in pairs(adj)do
            if swept[k] == nil then
                if k.isEnd then
                    return true
                else
                    if checkConnectEnd(k, swept) == true then
                        return true
                    end
                end
            end
        end
        return false
    end

    for k,v in pairs(fields) do
        local swept = {}
        if checkConnectEnd(k, swept) == false then
            for m,n in pairs(swept) do
                notConFields[m] = true
            end
        end
    end

end

function GameScene:onClickPause()
    local pausePanel = PausePanel.create(self)
    pausePanel.view:setPosition(s_uiinfo.popWin.position.x, s_uiinfo.popWin.position.y)


    self:game_pause()
end

function GameScene:game_pause()
    self.refcnt_gamepause = self.refcnt_gamepause + 1
    d_print("game_pause:[refcnt_gamepause]="..self.refcnt_gamepause)
    if self.refcnt_gamepause == 1 then
        self.view:unscheduleUpdate()
        if self.boss then
            self.boss:pauseAttack()
        end
    end
end

function GameScene:game_resume_callback()
    --assert(self.refcnt_gamepause>0)
    d_print("game_resume_callback:[refcnt_gamepause]="..self.refcnt_gamepause)
    if self.refcnt_gamepause > 0 then
        self.refcnt_gamepause = self.refcnt_gamepause - 1

        if self.refcnt_gamepause == 0 then
            local function update(delta)
            self:update(delta)
            end
            self.view:scheduleUpdateWithPriorityLua(update, 0)

            if self.boss then
                self.boss:resumeAttack()
            end
        end
    end
end

function GameScene:game_playAgain_callbak()
    self.warningPanel = WarningPanel.create(self, "GameScene_playAgain")
    self.warningPanel.view:setPosition(s_uiinfo.popWin.position.x, s_uiinfo.popWin.position.y)
    uiEffect.bounceIn(self.warningPanel.view)
end

function GameScene:game_level_callbak()
    --lkj test temp:
    self.warningPanel = WarningPanel.create(self, "GameScene_level")
    -- self.warningPanel = WarningPanel.create(self, "Common_leaveApp")
    self.warningPanel.view:setPosition(s_uiinfo.popWin.position.x, s_uiinfo.popWin.position.y)
    uiEffect.bounceIn(self.warningPanel.view)
end

function GameScene:warningPanelCallback(type, btIdx, panel)

    if type == "GameScene_playAgain" then

        if btIdx == 0 then
            self:game_resume_callback()
        else
            gameUtil.onClickPlayAgainThisLevel()
            panel:close()
        end
    elseif type == "GameScene_level" then
        if btIdx == 0 then
            self:game_resume_callback()
        else
            gameUtil.changeScene("level")
        end
    elseif type == "Common_leaveApp" then
        if btIdx == 0 then
        elseif btIdx == 2 then
            if #self.base_popWinStack == 1 then
                self:game_resume_callback()
            end
            panel:close()
        elseif btIdx == 1 then
            cc.Director:getInstance():endToLua()
        else

        end

    elseif type == "Pay_game_buyYuheng" then
        if btIdx == 0 then
            self:game_resume_callback()
        elseif btIdx == 1 then
            self.pchPanel = panel
            if pchCenter:order(pchCfg.item.YuHeng_10) == false then
                uiPopNotify:popString(self.widget, strDef.str_orderFail)
                self:game_resume_callback()
                panel:close()
                self.pchPanel = nil
            end
        else

        end
    elseif type == "Pay_game_buyFenji" then
        if btIdx == 0 then
            self:game_resume_callback()
        elseif btIdx == 1 then
            self.pchPanel = panel
            if pchCenter:order(pchCfg.item.FenJi_10) == false then
                uiPopNotify:popString(self.widget, strDef.str_orderFail)
                self:game_resume_callback()
                panel:close()
                self.pchPanel = nil
            end
        else

        end
    elseif type == "Pay_game_FuHuo" then
        if btIdx == 0 then
            self:game_fail()
        elseif btIdx == 1 then
            self.pchPanel = panel
            if pchCenter:order(pchCfg.item.FuHuo) == false then
                uiPopNotify:popString(self.widget, strDef.str_orderFail)
                self:game_fail()
                panel:close()
                self.pchPanel = nil
            end
        end
    elseif type == "GameScene_freeFuhuo" then
        if btIdx == 0 or btIdx == 3 then
            self:game_fail()
        elseif btIdx == 1 then
            self:onGameFuhuo()
            userData.spe_freeFuhuoLeft = userData.spe_freeFuhuoLeft - 1
            panel:close()
        end 
    elseif type == "Pay_game_Libao_Fuhuo" or type == "Pay_game_Libao_Fuhuo2" then
        if btIdx == 0 or btIdx == 3 then

            -- --lkj tmp
            -- self.pchPanel = panel
            -- pchCenter:order(pchCfg.item.FuHuoLiBao)
            -- pchCenter.curItem.processOk()
            
            -- return

            self:game_fail()
            
        elseif btIdx == 1 then
            panel.view:unscheduleUpdate()

            self.pchPanel = panel
            if pchCenter:order(pchCfg.item.FuHuoLiBao) == false then
                uiPopNotify:popString(self.widget, strDef.str_orderFail)
                self:game_fail()
                panel:close()
                self.pchPanel = nil
            end
        end 

    elseif type == "Pay_ChangwanGift" then

        if btIdx == 0 then

            -- --lkj tmp
            -- self.pchPanel = panel
            -- pchCenter:order(pchCfg.item.ChangWanLiBao)
            -- pchCenter.curItem.processOk()

            if gameData.status == _pp.gamestate_fail then
                if userData.spe_freeFuhuoLeft == 0 then
                    WarningPanel.create(self, "Pay_game_Libao_Fuhuo")
                else
                    self:wrapper_WarningPanel_create_freeFuhuo()
                end
            else
                self:game_win(0)
            end

        elseif btIdx == 1 then
            
            self.pchPanel = panel
            if pchCenter:order(pchCfg.item.ChangWanLiBao) == false then
                uiPopNotify:popString(self.widget, strDef.str_orderFail)
                panel:close()
                self.pchPanel = nil 
                
                if gameData.status == _pp.gamestate_fail then
                    if userData.spe_freeFuhuoLeft == 0 then
                        WarningPanel.create(self, "Pay_game_Libao_Fuhuo")
                    else
                        self:wrapper_WarningPanel_create_freeFuhuo()
                    end
                else
                    self:game_win(0)
                end
            end
        end 

    elseif type == "Guide_tip_wood" or
        type == "Guide_tip_key" or
        type == "Guide_tip_boss"

        then
        self:guide_itemFinish()
        self:game_resume_callback()
        panel:close()
    end
end

function GameScene:weapon_fenji()
    tmp_uiinfo:readInfoFromNode(self.curbt.view)
    local parent = self.curbt.view:getParent()
    uiEffect.FadeOut(self.curbt.view, 0.2, true)

    self.curbt = BubbleFenji:create()
    parent:addChild(self.curbt.view)
    -- uiEffect.FadeIn(self.curbt.view, 0.2)

    
    s_uiinfo.fenjibt:setInfoToNode(self.curbt.view)
    local jumpTo = cc.JumpTo:create(0.3, tmp_uiinfo.position, 50, 1)
    self.curbt.view:runAction(jumpTo)
end

function GameScene:weapon_fenji_ani(x,y)

    local scaleJian = {0.8, 1.0, 1.2, 1.4, 1.6}
    local scaleBz = {0.6, 0.9, 1.2, 1.5, 1.8}
    local lv = userData.weaponLv_fenji
    scaleJ = scaleJian[lv]
    scaleB = scaleBz[lv]

    -- body
    local ani1 = uiAnimation.createAutoRelease("fenjijian", false, 0.72)
    self.widget:addChild(ani1, _pp.z_epl_ani+2)
    ani1:setScale(scaleJ)
    ani1:setPosition(x,y - 400 + self.mapbbOffsetY)
    ani1:runAction(cc.MoveBy:create(0.22, cc.p(0,400)))

    local function ani2()
        -- local ani = uiAnimation.createAutoRelease("fenjibz", false, 0.42)
        -- self.widget:addChild(ani, _pp.z_epl_ani+1)
        -- ani:setScale(scaleB)
        -- ani:setPosition(x,y + self.mapbbOffsetY)
        local ani = self:ani_baozha_pos(x,y)
        ani:setScale(scaleB)
    end
    performWithDelay(self.widget, ani2, 0.3)
end

function GameScene:weapon_yuheng()
    AudioEngine.playEffect(sound.yuheng)

    -- tmp_uiinfo:readInfoFromNode(self.curbt.view)
    -- local parent = self.curbt.view:getParent()
    -- uiEffect.FadeOut(self.curbt.view, 0.2, true)

    -- self.curbt = BubbleYuheng:create()
    -- tmp_uiinfo:setInfoToNode(self.curbt.view)
    -- parent:addChild(self.curbt.view)
    -- uiEffect.FadeIn(self.curbt.view, 0.2)
    local delbbs = {}
    local key_hit
    local boss_hit
    local maxRow = #self.levelbubbles
    local delRowCnt = _userData.weaponLv_yuheng
    local b
    for irow = maxRow, maxRow - delRowCnt, -1 do
        if irow < 1 then
            break
        end
        rowTbl = self.levelbubbles[irow]
        for icol = 1,s_colCnt do
            b = rowTbl[icol]
            if b ~= 0 then
                if b.itype == pp.bt_key then
                    key_hit = b
                elseif b.itype == _pp.bt_boss then
                    boss_hit = b
                else
                    delbbs[#delbbs+1] = b
                end
            end
        end
    end

    --play ani
    local ani_row = maxRow - delRowCnt
    if ani_row < 1 then ani_row = 1 end
    local ani_x, ani_y = GameScene.bb_pos(ani_row, 9)
    local aniShan = uiAnimation.createAutoRelease("yuhengshan", false, 0.42)
    self.widget:addChild(aniShan, _pp.z_epl_ani+2)
    aniShan:setScale(1.5)
    aniShan:setPosition(ani_x,ani_y - 20 + self.mapbbOffsetY)
    aniShan:runAction(cc.MoveBy:create(0.4, cc.p(-450,0)))

    local function aniDian()
        local aniDian = uiAnimation.createAutoRelease("yuhengdian", false, 0.42)
        self.widget:addChild(aniDian, _pp.z_epl_ani+1)
        aniDian:setScale(1.0)
        aniDian:setPosition(_pp.center.x,ani_y + self.mapbbOffsetY)
    end
    performWithDelay(self.widget, aniDian, 0.2)
    


    if key_hit then
        self:logic_bbHitKey(key_hit)
        return
    else
        --delay process for optimize
        --                local function __delay1(sender)
        --                    self:gm_bbs_Explode(booms, curpos.x, curpos.y)
        --                end
        --                performWithDelay(self.view, __delay1, 0)

        self:gm_bbs_Explode(delbbs, _pp.visibleSize.width, _pp.visibleSize.height*0.5)

        gameData.status = _pp.gamestate_playing
    end

    if boss_hit then
        self:logic_bbHitBoss(boss_hit)
    end

    self.bGmProcessing = true
end

function GameScene:refreshWeaponCnt()
    if userData.weaponCnt_fenji == 0 then
        self.ui_weaponCnt_fenji:setString("+")
        self.ui_weaponCnt_fenji:setScale(0.85)
    else
        self.ui_weaponCnt_fenji:setString(string.format("%d", userData.weaponCnt_fenji))
        self.ui_weaponCnt_fenji:setScale(0.6)
    end
    if userData.weaponCnt_yuheng == 0 then
        self.ui_weaponCnt_yuheng:setString("+")
        self.ui_weaponCnt_yuheng:setScale(0.85)
    else
        self.ui_weaponCnt_yuheng:setString(string.format("%d", userData.weaponCnt_yuheng))
        self.ui_weaponCnt_yuheng:setScale(0.6)
    end
end


function GameScene:logic_bbHitBoss(boss)
    boss:onHit()
end

function GameScene:boss_xpAttack(boss, bullets)
    local curRowCnt = #self.levelbubbles

    local function findASlotThatHasNeighbour()
        local randrow
        if curRowCnt == 1 then
            randrow = 1
        else
            randrow = math.random(curRowCnt-1)
        end
        local randcol = math.random(s_colCnt)

        for rlooper = 0, curRowCnt-1 do
            local r = randrow + rlooper
            if r > curRowCnt - 1 then r = r - (curRowCnt-1) end

            for clooper = 0, s_colCnt-1 do
                local c = randcol + clooper
                if c > s_colCnt then c = c - s_colCnt end

                local bb = self.levelbubbles[r][c]
                if not bb then
                    assert(bb, "bb == nil...")
                end
                if bb == 0 then
                    for k,v in ipairs(s_dirs)do
                        local b = self:getBB_around_bb(r,c,v)
                        if b then
                            return r, c
                        end
                    end
                end
            end
        end
        return nil
    end

    for k,v in pairs(bullets)do
        local r,c = findASlotThatHasNeighbour()
        if r then
            local bb = s_createBBbyType(v)

            if bb ~= nil then
                assert(bb.view, "view not init...")
                self.bbLayer:addChild(bb.view)
                bb.view:setLocalZOrder(pp.z_mapbb)
                self:bb_attachToMap(bb, r, c, true)
            end

            local x, y = GameScene.bb_pos(r, c)
            -- local oldx,oldy = boss.view:getPosition()
            bb.view:setOpacity(0)
            bb.view:setPosition(boss.view:getPosition())
            bb.view:runAction(
                cc.Spawn:create(
                    cc.FadeIn:create(0.2),
                    cc.MoveTo:create(0.5, cc.p(x, y))
                )
            )
        else
            return
        end
    end

    AudioEngine.playEffect(sound.bossAttack)
end

function GameScene:boss_xpRefresh(percent)
    self.ui_boss_xpprogress:setPercentage(percent*100)
end

function GameScene:boss_lifeRefresh(lifecnt)
    local hpimage = {self.ui_boss_hp1, self.ui_boss_hp2, self.ui_boss_hp3, self.ui_boss_hp4}
    for i = 1,4 do
        if i <= lifecnt then
            hpimage[i]:setVisible(true)
        else
            hpimage[i]:setVisible(false)
        end
    end
end

function GameScene:boss_genProtection()
    AudioEngine.playEffect(sound.bossDefence)

    local dirs = {dirR,dirRB,dirLB,dirL}
    local protect = gameData.leveldata.boss.protect
    for k,v in pairs(dirs)do
        local b = self:getBB_around_bb(self.boss.row,self.boss.col,v)
        if not b then
            local row, col = self:getBB_around_rc(self.boss.row,self.boss.col,v)
            local typeidx = math.random(#protect)
            local newtype = protect[typeidx]
            local bb = s_createBBbyType(newtype)
            self.bbLayer:addChild(bb.view)
            bb.view:setLocalZOrder(pp.z_mapbb)
            self:bb_attachToMap(bb, row, col, true)
            uiEffect.bounceIn(bb.view)
        end
    end
end

-- function GameScene:bb_CheckAndExplode(bb)
-- --          1        2
-- --
-- --      6                  3
-- --          
-- --          5        4   
--     local it = bb.itype
--     local unsortedTbl = {}
     
--     local bbs = self.levelbubbles
--     local rowcnt = #bbs
      
--     function checkExplode(tbl, r, c)
--         if bbs[r][c] == nil then
--             assert(false,"")
--          d_print("centerbb == ni")
--         end
--         local centerbb = bbs[r][c]
--         --exist, itype same, has not checked
--         if centerbb ~= 0 and centerbb.itype == it and centerbb.bWillExplode == false then
            
--             centerbb.bWillExplode = true
--             tbl[#tbl+1] = centerbb
     
--             local dirs = {dirLT,dirRT,dirR,dirRB,dirLB,dirL}
--             for k,v in ipairs(dirs) do
--                 local row, col = self:getBB_around_rc(r, c, v)
--                -- if row > 0 and row <= rowcnt and col ~= 0 then 
--                 if bbs[row] and bbs[row][col]  and bbs[row][col] ~= 0 then
--                     checkExplode(tbl,row,col) 
--                 end
--             end
                          
--         end
--     end
          
--     checkExplode(unsortedTbl, bb.row, bb.col)
--     d_print("unsortedtbl len: "..#unsortedTbl)
--     if #unsortedTbl == 1 then
--      --curbt
--      unsortedTbl[1].bWillExplode = false
--     else
 
--         local explodelen = #unsortedTbl
--         local adjacentEplTbl = {}
--         local touchwallTbl = {}

--         for i = 1, explodelen do
--             local samecolorbb = unsortedTbl[i]
 
--             local sweptTbl = {}
--             local bTouchWall = false
--             local dirs = {dirLT,dirRT,dirR,dirRB,dirLB,dirL}
 
--             function precessAdjacent(r, c)
            
--                 for k,v in ipairs(dirs) do
--                     local row, col = self:getBB_around_rc(r, c, v)
--                     if bbs[row] and bbs[row][col] and bbs[row][col] ~= 0 then
--                         local bb = bbs[row][col]

--                         if bb.bWillExplode == false then    --跳过那些已经扫描过被定为要消去的泡泡

--                             local itTouchwall = false
--                             for m,n in pairs(touchwallTbl) do
--                                 if m == bb then
--                                     itTouchwall = true
--                                     break
--                                 end
--                             end
 
--                             if itTouchwall == true then     --该泡泡触墙
--                                 break
--                             end
                            
--                             local itSwept = false
--                             for m,n in pairs(sweptTbl) do
--                                 if m == bb then
--                                     return true
--                                 end
--                             end
                                                        
--                             if itSwept == false then
--                                 sweptTbl[bb] = true     --record it
--                                 if row == 1 then 
--                                     bTouchWall = true
--                                     break
--                                 else
--                                     precessAdjacent(row, col)
--                                 end
--                             end
                           
--                         end
                        
--                     end
--                 end
--             end
 
--             precessAdjacent(samecolorbb.row, samecolorbb.col)

--             if bTouchWall == true then
--                 --record to swept touch wall table
--                 for k,v in pairs(sweptTbl) do 
--                     touchwallTbl[k] = true
--                 end
--             else
--                 for k,v in pairs(sweptTbl) do 
--                     k.bWillExplode = true
--                     adjacentEplTbl[#adjacentEplTbl+1] = k
--                 end
--             end

--         end
 


--         local function doExplode()
--             for k,v in pairs(unsortedTbl) do
--                 v.view:removeFromParent(true)
--                 self.levelbubbles[v.row][v.col] = 0
--             end

--             for k,v in pairs(adjacentEplTbl) do
--                 v.view:removeFromParent(true)
--                 self.levelbubbles[v.row][v.col] = 0
--             end
--         end
--         self.view:runAction( 
--             cc.Sequence:create(
--                 cc.DelayTime:create(0.1) ,
--                 cc.CallFunc:create(doExplode), 
--                 cc.CallFunc:create(function() 
--                                             self.bExploding = false 
--                                              end)
--                 )
--         )

--         self.bExploding = true
        
--     end
     
 
-- end

--function GameScene:

    












--
--
--
--local HelloScene = class("HelloScene",function()
--    return cc.Scene:create()
--end)
--
--function HelloScene.create()
--    local scene = HelloScene.new()
--    scene:addChild(scene:createLayerFarm())
--    scene:addChild(scene:createLayerMenu())
--    return scene
--end
--
--
--function HelloScene:ctor()
--    self.visibleSize = cc.Director:getInstance():getVisibleSize()
--    self.origin = cc.Director:getInstance():getVisibleOrigin()
--    self.schedulerID = nil
--end
--
--function HelloScene:playBgMusic()
--    local bgMusicPath = cc.FileUtils:getInstance():fullPathForFilename("background.mp3") 
--    cc.SimpleAudioEngine:getInstance():playMusic(bgMusicPath, true)
--    local effectPath = cc.FileUtils:getInstance():fullPathForFilename("effect1.wav")
--    cc.SimpleAudioEngine:getInstance():preloadEffect(effectPath)
--end
--
--function HelloScene:creatDog()
--    local frameWidth = 105
--    local frameHeight = 95
--
--    -- create dog animate
--    local textureDog = cc.Director:getInstance():getTextureCache():addImage("dog.png")
--    local rect = cc.rect(0, 0, frameWidth, frameHeight)
--    local frame0 = cc.SpriteFrame:createWithTexture(textureDog, rect)
--    rect = cc.rect(frameWidth, 0, frameWidth, frameHeight)
--    local frame1 = cc.SpriteFrame:createWithTexture(textureDog, rect)
--
--    local spriteDog = cc.Sprite:createWithSpriteFrame(frame0)
--    spriteDog:setPosition(self.origin.x, self.origin.y + self.visibleSize.height / 4 * 3)
--    spriteDog.isPaused = false
--
--    local animation = cc.Animation:createWithSpriteFrames({frame0,frame1}, 0.5)
--    local animate = cc.Animate:create(animation);
--    spriteDog:runAction(cc.RepeatForever:create(animate))
--
--    -- moving dog at every frame
--    local function tick()
--        if spriteDog.isPaused then return end
--        local x, y = spriteDog:getPosition()
--        if x > self.origin.x + self.visibleSize.width then
--            x = self.origin.x
--        else
--            x = x + 2
--        end
--
--        spriteDog:setPositionX(x)
--    end
--
--    self.schedulerID = cc.Director:getInstance():getScheduler():scheduleScriptFunc(tick, 0, false)
--
--    return spriteDog
--end
--
---- create farm
--function HelloScene:createLayerFarm()
--    local layerFarm = cc.Layer:create()
--    -- add in farm background
--    local bg = cc.Sprite:create("farm.jpg")
--    bg:setPosition(self.origin.x + self.visibleSize.width / 2 + 80, self.origin.y + self.visibleSize.height / 2)
--    layerFarm:addChild(bg)
--
--    -- add land sprite
--    for i = 0, 3 do
--        for j = 0, 1 do
--            local spriteLand = cc.Sprite:create("land.png")
--            spriteLand:setPosition(200 + j * 180 - i % 2 * 90, 10 + i * 95 / 2)
--            layerFarm:addChild(spriteLand)
--        end
--    end
--
--    -- add crop
--    local frameCrop = cc.SpriteFrame:create("crop.png", cc.rect(0, 0, 105, 95))
--    for i = 0, 3 do
--        for j = 0, 1 do
--            local spriteCrop = cc.Sprite:createWithSpriteFrame(frameCrop);
--            spriteCrop:setPosition(210 + j * 180 - i % 2 * 90, 40 + i * 95 / 2)
--            layerFarm:addChild(spriteCrop)
--        end
--    end
--
--    -- add moving dog
--    local spriteDog = self:creatDog()
--    layerFarm:addChild(spriteDog)
--
--    -- handing touch events
--    local touchBeginPoint = nil
--    local function onTouchBegan(touch, event)
--        local location = touch:getLocation()
--        --cclog("onTouchBegan: %0.2f, %0.2f", location.x, location.y)
--        touchBeginPoint = {x = location.x, y = location.y}
--        spriteDog.isPaused = true
--        -- CCTOUCHBEGAN event must return true
--        return true
--    end
--
--    local function onTouchMoved(touch, event)
--        local location = touch:getLocation()
--        --cclog("onTouchMoved: %0.2f, %0.2f", location.x, location.y)
--        if touchBeginPoint then
--            local cx, cy = layerFarm:getPosition()
--            layerFarm:setPosition(cx + location.x - touchBeginPoint.x,
--                cy + location.y - touchBeginPoint.y)
--            touchBeginPoint = {x = location.x, y = location.y}
--        end
--    end
--
--    local function onTouchEnded(touch, event)
--        local location = touch:getLocation()
--        --cclog("onTouchEnded: %0.2f, %0.2f", location.x, location.y)
--        touchBeginPoint = nil
--        spriteDog.isPaused = false
--    end
--
--    local listener = cc.EventListenerTouchOneByOne:create()
--    listener:registerScriptHandler(onTouchBegan,cc.Handler.EVENT_TOUCH_BEGAN )
--    listener:registerScriptHandler(onTouchMoved,cc.Handler.EVENT_TOUCH_MOVED )
--    listener:registerScriptHandler(onTouchEnded,cc.Handler.EVENT_TOUCH_ENDED )
--    local eventDispatcher = layerFarm:getEventDispatcher()
--    eventDispatcher:addEventListenerWithSceneGraphPriority(listener, layerFarm)
--
--    local function onNodeEvent(event)
--        if "exit" == event then
--            cc.Director:getInstance():getScheduler():unscheduleScriptEntry(self.schedulerID)
--        end
--    end
--    layerFarm:registerScriptHandler(onNodeEvent)
--
--    return layerFarm
--end
--
---- create menu
--function HelloScene:createLayerMenu()
--
--    local layerMenu = cc.Layer:create()
--    local menuPopup, menuTools, effectID
--
--    local function menuCallbackClosePopup()
--        -- stop test sound effect
--        cc.SimpleAudioEngine:getInstance():stopEffect(effectID)
--        menuPopup:setVisible(false)
--    end
--
--    local function menuCallbackOpenPopup()
--        -- loop test sound effect
--        local effectPath = cc.FileUtils:getInstance():fullPathForFilename("effect1.wav")
--        effectID = cc.SimpleAudioEngine:getInstance():playEffect(effectPath)
--        menuPopup:setVisible(true)
--    end
--
--    -- add a popup menu
--    local menuPopupItem = cc.MenuItemImage:create("menu2.png", "menu2.png")
--    menuPopupItem:setPosition(0, 0)
--    menuPopupItem:registerScriptTapHandler(menuCallbackClosePopup)
--    menuPopup = cc.Menu:create(menuPopupItem)
--    menuPopup:setPosition(self.origin.x + self.visibleSize.width / 2, self.origin.y + self.visibleSize.height / 2)
--    menuPopup:setVisible(false)
--    layerMenu:addChild(menuPopup)
--
--    -- add the left-bottom "tools" menu to invoke menuPopup
--    local menuToolsItem = cc.MenuItemImage:create("menu1.png", "menu1.png")
--    menuToolsItem:setPosition(0, 0)
--    menuToolsItem:registerScriptTapHandler(menuCallbackOpenPopup)
--    menuTools = cc.Menu:create(menuToolsItem)
--    local itemWidth = menuToolsItem:getContentSize().width
--    local itemHeight = menuToolsItem:getContentSize().height
--    menuTools:setPosition(self.origin.x + itemWidth/2, self.origin.y + itemHeight/2)
--    layerMenu:addChild(menuTools)
--
--    return layerMenu
--end

--return HelloScene
--return GameScene




